首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言指針深度解析:類型本質、運算符、優勢與空指針規範

     編輯:關於C語言

指針類型的本質:復合數據類型

Joel Spolsky 認為指針理解是天賦,但通過系統分析仍可掌握核心。指針是復合類型,包含兩層含義:

  1. 指針本身:一個內存地址,大小由機器字長決定(32位 4 字節,64位 8 字節)
  2. 指向的對象:該地址上存儲的數據,類型由聲明決定

聲明拆解範例

聲明指針本身類型去掉 * 後(指向對象類型)語義
int *p;int *int指向整數的指針
int **p;int **int *指向「指向整數的指針」的指針
int (*parValue)[3];int (*)[3]int [3]指向「含 3 個整數的數組」的指針
int (*pFun)();int (*)()int ()指向「無參返回 int 的函數」的指針

sizeof(指針) 永遠等於機器字長


void *p = malloc(100);
sizeof(p);  // 4 (32位) / 8 (64位) —— 與分配的 100 字節無關

char str[] = "Hello";
char *p = str;
sizeof(p);  // 同樣是 4/8

void Func(char str[100]) {
    sizeof(str);  // 此處 str 退化為指針,結果仍為 4/8
}

結論:sizeof(指針變量) 只反映指針自身大小,無法獲取動態分配內存塊大小。

& 與 *:互逆操作

  • &x:取變量 x 的地址 → 得到指針(指針本身)
  • *p:取指針 p 指向地址上的內容 → 得到指向對象

適用對象:變量、數組、函數、類成員等。

使用指針的 7 大核心優勢

  1. 動態數組:malloc/new 運行時決定大小
  2. 通用訪問:同一指針遍歷多個同類型變量
  3. 模擬傳引用:函數參數傳地址,修改實參值
  4. 節省調用開銷:大結構體傳地址避免拷貝
  5. 動態數據結構:鏈表、樹、哈希表的基石
  6. 底層內存直接操作:硬件寄存器映射、DMA、裸機編程
  7. 高效遍歷:指針掃描字符串/數組比下標快

空指針規範:為什麼推薦 0L?

常見定義對比


#define NULL 0
#define NULL (char *)0
#define NULL (void *)0
#define NULL 0L   // 推薦

深度解析

  • C 標準:整數常量表達式 0 在指針上下文中自動轉為空指針
  • 但空指針內部表示不一定是全 0 比特位(某些架構非零)
  • 0L(long 型 0)是「值為 0 的整數常量表達式」,最符合標準定義,跨平台最安全
  • Windows 2000 等系統將進程地址空間低端(如 0x00000000~0x0000FFFF)保留給內核,用戶訪問觸發「非法指針」異常,這正是空指針保護機制

指針編程三大鐵律

  1. 未使用的指針初始化為 NULL
  2. 分配前後必須判斷指針有效性
  3. 釋放指向內存後,指針本身置 NULL

經典錯誤:野指針


void Test() {
    char *str = malloc(100);
    strcpy(str, "hello");
    free(str);
    if (str != NULL) {  // ❌ str 成野指針,非 NULL 但不可用
        strcpy(str, "world");  // 破壞堆元數據,後果不可控
    }
}

修正


free(str);
str = NULL;  // ✅ 防止野指針誤用

C++ 補充:成員指針大小不固定

  • 普通對象指針:4/8 字節
  • 指向類成員的指針:可能更大(多重繼承、虛繼承、虛函數需額外偏移信息)
  • 靜態成員指針:普通函數/數據指針,大小固定

總結

指針是「地址」與「類型」的復合體。掌握 指針本身值(地址) 與 指向對象(類型語義) 的二元性質,配合 &/* 互逆操作、sizeof 特性、空指針規範與三大編程鐵律,即可構建健壯、高效的 C/C++ 系統代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved