8.c語言指針

內存管理

C語言中,棧內存(局部變量)自動分配/釋放,靜態區(全局、靜態變量)編譯時分配;堆內存需手動分配/釋放,核心函數有3個:

?malloc函數

  • 原型:void* malloc(size_t size);
  • 功能:在堆上分配連續的size字節內存,不初始化內存內容。
  • 返回值:成功則返回指向內存首地址的void*指針;失敗返回NULL(如內存不足)。
  • 用法示例:
    int *p = (int*)malloc(5 * sizeof(int)); // 分配能存5個int的內存(需強轉) 
    if (p == NULL) { // 檢查分配失敗 printf("malloc failed\n"); return -1; 
    } 
    

?calloc函數

  • 原型:void* calloc(size_t num, size_t size);
  • 功能:在堆上分配**num個大小為size的連續內存塊**,且自動初始化為0
  • 返回值:成功返回內存首地址void*;失敗返回NULL
  • malloc的區別:calloc會初始化內存為0,且參數是“個數+單個大小”(malloc是總字節數)。
  • 用法示例:
    int *q = (int*)calloc(5, sizeof(int)); // 分配5個int,每個初始化為0 
    if (q == NULL) { /* 錯誤處理 */ } 
    

?realloc函數

  • 原型:void* realloc(void* ptr, size_t new_size);
  • 功能:調整已分配內存塊的大小(基于ptr指向的原內存)。
  • 調整邏輯:
    • 若原內存后有足夠空間,直接擴展,返回原地址;
    • 若空間不足,重新分配新內存塊,復制原數據到新塊,釋放原內存,返回新地址;
    • ptrNULL,等價于malloc(new_size);若new_size為0,等價于free(ptr)(不同實現有差異)。
  • 返回值:成功返回新內存首地址;失敗返回NULL(原ptr指向的內存不變)。
  • 用法示例:
    p = realloc(p, 10 * sizeof(int)); // 將p的內存從5個int擴容到10個int 
    if (p == NULL) { /* 錯誤處理(原p內存仍有效) */ } 
    

內存釋放函數free

  • 原型:void free(void* ptr);
  • 功能:將ptr指向的動態分配的堆內存歸還給系統,避免內存泄漏。
  • 注意點:
    • ptr必須是malloc/calloc/realloc返回的指針(否則行為未定義,如野指針、棧內存指針);
    • 釋放后ptr變為懸空指針(指向無效內存),需手動置NULL避免誤用;
    • 不可重復釋放同一指針(未定義行為,可能崩潰)。
  • 用法示例:
    free(p); 
    p = NULL; // 釋放后置空,避免懸空指針 
    

常見問題與注意事項

  1. 分配失敗檢查:調用malloc/calloc/realloc后,必須判斷返回值是否為NULL,否則后續操作空指針會崩潰。
  2. 內存泄漏:動態分配的內存未用free釋放,程序結束前不會自動回收,長期運行會耗盡內存。
  3. 懸空指針free后指針未置NULL,后續若誤操作(如解引用、再次free)會觸發未定義行為。
  4. 內存越界:訪問分配內存范圍外的地址(如p[5]但只分配了5個int,索引0~4有效),會破壞內存結構,導致程序崩潰或數據錯亂。
  5. realloc的風險:若realloc失敗返回NULL,原ptr仍有效,需單獨處理(如備份原指針)。

C語言動態內存管理核心是malloc/calloc/realloc分配堆內存,free釋放內存。需牢記分配必檢查、釋放要置空、避免越界/重復釋放,才能安全管理內存。

指針

一、指針的基本概念

  1. 定義與聲明

    指針是存儲另一個變量的地址的變量。其聲明形式如下:

    數據類型 *指針名;

    其中數據類型是指針指向的數據類型的說明符,而*表示這是一個指針變量。

    示例:

    int *p; // p 是一個指向整數的指針
  2. 取地址運算符(&)和解引用運算符(*)

    • &:取地址運算符,用于獲取變量的地址。

      int a = 5;
      int *p = &a; // p 現在保存了 a 的地址
    • *:解引用運算符,訪問指針所指向的值。

      int value = *p; // value 將會是 5,即 p 所指向位置的值

二、指針與數組

在C語言中,數組名實際上是一個指向數組第一個元素的常量指針。這意味著你可以使用指針來遍歷數組。

示例:

int arr[5] = {1, 2, 3, 4, 5};
int *p = arr; // 等價于 int *p = &arr[0];
for (int i = 0; i < 5; ++i) {printf("%d ", *(p + i)); // 使用指針訪問數組元素
}

三、指針與函數

  1. 傳遞指針作為參數

    通過傳遞指針給函數,可以在函數內部修改調用者提供的變量的值。

    示例:

    void increment(int *n) {(*n)++;
    }int main() {int number = 10;increment(&number);// number 現在是 11
    }
  2. 返回指針

    函數可以返回一個指針,但需要小心處理動態分配的內存以避免內存泄漏。

    示例:

    int* createArray(int size) {return malloc(size * sizeof(int));
    }

四、指針的算術運算

指針支持加法和減法操作,允許你移動指針指向不同的內存位置。

  • 指針加法:將指針向前移動若干個元素的位置。

    int arr[] = {1, 2, 3};
    int *p = arr;
    p++; // p 現在指向 arr[1]
  • 指針減法:將指針向后移動若干個元素的位置或計算兩個指針之間的距離。

五、多級指針

指針本身也可以有地址,即指向指針的指針或多級指針。

示例:

int a = 10;
int *p = &a; // p 是一個指向 int 的指針
int **pp = &p; // pp 是一個指向 int* 類型指針的指針

六、void指針

void*是一種特殊類型的指針,它可以指向任何數據類型的變量,但它不能直接解引用,因為編譯器不知道它實際指向的數據類型。

示例:

void* ptr;
int a = 10;
ptr = &a;
int *intptr = (int*)ptr; // 需要強制轉換為具體類型才能解引用

七、指針的安全注意事項

  • 空指針檢查:在使用指針前,應該檢查它是否為NULL

    if (ptr != NULL) {// 安全使用指針
    }
  • 避免懸空指針:當指針指向的內存被釋放后,該指針變成懸空指針。訪問懸空指針會導致未定義行為。

  • 正確管理動態內存:使用malloc, calloc, realloc分配內存,并確保使用free釋放不再使用的內存以避免內存泄漏。

函數指針

在C語言中,指針不僅可以指向變量,還可以指向函數。函數指針是一種特殊的指針類型,它存儲的是函數的起始地址,可以通過這個指針來調用函數。

一、定義和聲明函數指針

定義一個函數指針需要指定其指向的函數的返回類型以及參數列表。其基本語法如下:

返回類型 (*指針名)(參數類型列表);

例如,假設有一個返回類型為int,接受兩個int類型參數的函數,那么對應的函數指針可以這樣定義:

int add(int a, int b) {return a + b;
}int (*funcPtr)(int, int); // 定義一個函數指針

二、初始化函數指針

你可以將函數的名字賦值給函數指針,因為函數名本質上是指向函數入口點的指針。例如:

funcPtr = add; // 將add函數的地址賦給funcPtr

或者直接在聲明時初始化:

int (*funcPtr)(int, int) = add;

三、通過函數指針調用函數

一旦函數指針被初始化,就可以像普通函數那樣使用它來調用函數:

int result = funcPtr(3, 4); // 相當于調用add(3, 4)
printf("%d\n", result); // 輸出7

四、函數指針作為參數傳遞

函數指針可以作為參數傳遞給其他函數,這在實現回調機制時非常有用。例如:

void executeOperation(int (*operation)(int, int), int a, int b) {printf("Result: %d\n", operation(a, b));
}int main() {executeOperation(add, 5, 3); // 傳遞add函數的指針return 0;
}

五、函數指針數組

你也可以創建一個函數指針數組,用于存儲多個函數指針。這對于實現類似多態的行為很有幫助。

int subtract(int a, int b) {return a - b;
}int main() {int (*operations[2])(int, int) = {add, subtract}; // 函數指針數組int result1 = operations[0](10, 5); // 調用addint result2 = operations[1](10, 5); // 調用subtractprintf("Add: %d, Subtract: %d\n", result1, result2);return 0;
}

六、注意事項

  • 類型匹配:函數指針的類型必須與它指向的函數的簽名完全匹配(包括返回類型和參數列表)。
  • 空指針檢查:如同其他類型的指針一樣,使用前應確保函數指針不是NULL,避免未定義行為。
  • 函數指針與函數本身的區別:雖然函數名可以直接賦值給函數指針,但它們并不完全相同。函數名是編譯時常量,而函數指針是一個變量,可以在運行時改變其所指向的函數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/90717.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/90717.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/90717.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用GPU訓練模型

本文代碼詳解參考&#xff1a; 模型訓練基礎流程-CSDN博客 目錄 為什么要用GPU訓練模型 什么是CUDA 利用GPU訓練—方式一(.cuda()) 利用GPU訓練—方式二 (.to()) Google Colaboratory 為什么要用GPU訓練模型 用 GPU 訓練模型的核心原因是GPU 的硬件架構和計算特性&#…

Matlab學習筆記:自定義函數

MATLAB 學習筆記&#xff1a;自定義函數自定義函數是MATLAB編程的基礎&#xff0c;它允許你將重復代碼封裝成可重用的模塊&#xff0c;提高代碼的可讀性和效率。本筆記將覆蓋所有重點知識點&#xff0c;包括語法細節、輸入輸出處理、函數文件管理、錯誤處理等。我會用自然易懂的…

【數學建模 | Matlab】二維繪圖 和 三維繪圖

- 第 115 篇 - Date: 2025 - 07 - 23 Author: 鄭龍浩&#xff08;仟墨&#xff09; 續寫上一篇&#xff0c;如下文章&#xff1a; 【數學建模|Matlab】Matlab「基礎知識」和「基礎操作」 五 二維繪圖 1 舉例 % 二維平面繪圖&#xff08;擴展至 -2π 到 2π&#xff09; x …

MCP (Model Context Protocol) 與 HTTP API:大模型時代的通信新范式

MCP (Model Context Protocol) 與 HTTP API&#xff1a;大模型時代的通信新范式在數字世界的兩端&#xff0c;API 扮演著不可或缺的橋梁角色。我們熟知的 HTTP API 是 Web 互聯互通的基石&#xff0c;驅動著無數應用程序的交互。然而&#xff0c;隨著大型語言模型&#xff08;L…

CentOS 搭建 Docker 私有鏡像倉庫

CentOS 搭建 Docker 私有鏡像倉庫 搭建 Docker 私有鏡像倉庫能為團隊提供高效、安全的鏡像管理方案。下面將詳細介紹每個步驟的操作細節&#xff0c;其中命令部分均用代碼塊展示。 一、環境準備 要搭建 Docker 私有鏡像倉庫&#xff0c;首先得確保服務器環境符合要求&#xff0…

Zookeeper的簡單了解

Zookeeper的簡單了解 Zookeeper是一個為分布式應用程序提供協調服務的中間件。 主要作用有三點&#xff1a;分布式鎖、注冊中心、配置管理、。 特點有讀寫速度快&#xff08;內存存儲&#xff09;、有監聽機制&#xff08;用于發布訂閱&#xff09;、保證了順序一致性&#xff…

Android Fragment 全解析

在 Android 開發中&#xff0c;Fragment 是構建靈活界面的核心組件 —— 它既能像 “迷你 Activity” 一樣包含布局和邏輯&#xff0c;又能靈活地嵌入到不同 Activity 中復用。無論是平板的多面板布局&#xff0c;還是手機的單頁切換&#xff0c;Fragment 都能讓界面適配更高效…

0-1BFS(雙端隊列,洛谷P4667 [BalticOI 2011] Switch the Lamp On 電路維修 (Day1)題解)

對于權重為0或1的路徑搜索中&#xff0c;使用雙端隊列可以對最短路問題進行時間復雜度的優化&#xff0c;由于優先隊列的O(longn)級別的插入時間&#xff0c;對于雙端隊列O(1)插入可以將時間復雜度減少至O(M); https://www.luogu.com.cn/problem/P4667 #include<bits/stdc…

基于LNMP架構的分布式個人博客搭建

1.運行環境主機主機名系統服務192.168.75.154Server-WebLinuxWeb192.168.75.155Server-NFS-DNSLinuxNFS/DNS2.基礎配置配置主機名&#xff0c;靜態IP地址開啟防火墻并配置部分開啟SElinux并配置服務器之間使用同ntp.aliyun.com進行時間同步服務器之間使用用ntp.aliyun.com進行時…

基于開源AI智能名片鏈動2+1模式S2B2C商城小程序的人格品牌化實現路徑研究

摘要&#xff1a;在數字化消費時代&#xff0c;人格品牌化已成為企業突破同質化競爭的核心策略。本文以開源AI智能名片、鏈動21模式與S2B2C商城小程序的融合為切入點&#xff0c;構建“技術賦能-關系重構-價值共生”的人格品牌化理論框架。通過分析用戶觸達、信任裂變與價值沉淀…

設計模式十一:享元模式(Flyweight Pattern)

享元模式是一種結構型設計模式&#xff0c;它通過共享對象來最小化內存使用或計算開銷。這種模式適用于大量相似對象的情況&#xff0c;通過共享這些對象的公共部分來減少資源消耗。基本概念享元模式的核心思想是將對象的內在狀態&#xff08;不變的部分&#xff09;和外在狀態…

Webpack/Vite 終極指南:前端開發的“渦輪增壓引擎“

開篇:當你的項目變成"俄羅斯套娃" "我的index.js怎么引入了87個文件?!" —— 這是每個前端開發者第一次面對復雜項目依賴時的真實反應。別擔心,今天我要帶你認識兩位"打包俠":老牌勁旅Webpack和新銳黑馬Vite 一、構建工具:前端世界的&qu…

Windows 下配置 GPU 用于深度學習(PyTorch)的完整流程

1. 安裝 NVIDIA 顯卡驅動 前往 NVIDIA官網 下載并安裝適合你顯卡型號&#xff08;如 5070Ti&#xff09;的最新版驅動。下載 NVIDIA 官方驅動 | NVIDIA安裝完成后建議重啟電腦。 2. 安裝 CUDA Toolkit 前往 CUDA Toolkit 下載頁。 選擇 Windows、x86_64、你的系統版本&#…

詳解力扣高頻SQL50題之180. 連續出現的數字【困難】

傳送門&#xff1a;180. 連續出現的數字 題目 表&#xff1a;Logs -------------------- | Column Name | Type | -------------------- | id | int | | num | varchar | -------------------- 在 SQL 中&#xff0c;id 是該表的主鍵。 id 是一個自增列。 找出所有至少連續…

VSCode 報錯 Error: listen EACCES: permission denied 0.0.0.0:2288

使用 npm run dev 啟動項目時報錯&#xff1a;error when starting dev server: Error: listen EACCES: permission denied 0.0.0.0:2288at Server.setupListenHandle [as _listen2] (node:net:1881:21)at listenInCluster (node:net:1946:12)at Server.listen (node:net:2044:…

[2025CVPR-圖象超分辨方向]DORNet:面向退化的正則化網絡,用于盲深度超分辨率

1. ?問題背景與挑戰? 盲深度超分辨率&#xff08;Blind Depth Super-Resolution, DSR&#xff09;的目標是從低分辨率&#xff08;LR&#xff09;深度圖中恢復高分辨率&#xff08;HR&#xff09;深度圖&#xff0c;但現有方法在真實場景下面臨顯著挑戰&#xff1a; ?已知…

關系與邏輯運算 —— 寄存器操作的 “入門鑰匙”

前言 哈嘍大家好&#xff0c;這里是 Hello_Embed 的新一篇學習筆記。在前文中&#xff0c;我們學習了如何用結構體指針操作硬件寄存器&#xff0c;而寄存器的配置往往離不開位運算和條件判斷 —— 比如通過邏輯運算精準修改某幾位的值&#xff0c;通過關系運算判斷硬件狀態。這…

使用 Python 將 CSV 文件轉換為帶格式的 Excel 文件

在日常的數據處理和報表生成工作中&#xff0c;CSV 格式因其簡潔性而被廣泛采用。但在展示數據時&#xff0c;CSV 文件往往缺乏格式和結構化樣式&#xff0c;不利于閱讀與分析。相比之下&#xff0c;Excel 格式&#xff08;如 .xlsx&#xff09;不僅支持豐富的樣式設置&#xf…

每天讀本書-《如何度過每天的24小時》

全景式書籍探索框架 1. “這本書是關于什么的&#xff1f;”——核心定位 一句話核心思想&#xff1a;這本書的核心并非教你如何高效地工作&#xff0c;而是倡導你將工作之外的“自由時間”視為一個“內在的另一天”&#xff0c;并投入智力與熱情去經營它&#xff0c;從而獲得精…

前端開發 React 狀態優化

為了更深入地理解 React 狀態管理的性能問題及其解決方案&#xff0c;本文將詳細分析 React Context 和 State 的性能問題&#xff0c;配以示例代碼說明優化策略。之后&#xff0c;討論 Redux 作為不可變庫的性能問題&#xff0c;并引出 Immer 作為優化解決方案。1. React Stat…