首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C 語言結構體指針解引用空指針導致 Crash 經典案例

     編輯:程式設計綜合問答

崩潰代碼

typedef struct Data {
    int arr[10];
    int* p_low;
    int* p_high;
} Data;

int main() {
    Data* data = NULL;
    printf("%p\n", data->arr);          // 1. 未崩潰:arr 是柔性數組/固定數組,偏移量編譯期可知
    printf("%p\n", &(data->arr[1]));    // 2. 未崩潰:同理,偏移量計算不解引用
    printf("%p\n", data->p_low);        // 3. 崩潰:p_low 是指針成員,需解引用 data 讀取其值
    return 0;
}

記憶體模型解析

表達式操作是否解引用 data結果
data->arr取數組首地址(結構體起始偏移 0)否(編譯期常量偏移)輸出 0x0
&(data->arr[1])取元素地址(偏移 sizeof(int))否輸出 0x4
data->p_low讀取指針成員值(偏移 40/48 字節)是(需讀取 0x0+offset 處內存)Segmentation Fault

核心原則

  • -> 操作符隱含解引用:ptr->member 等價於 (*ptr).member。
  • 若 ptr == NULL,任何嘗試讀取/寫入成員內存的操作均導致未定義行為(通常 Crash)。
  • 數組成員(非指針)地址計算僅涉及偏移量,不讀取內存內容,故「僥倖」不崩潰,但屬於 UB,嚴禁依賴。

修正模式

// 正確:分配內存後再訪問
Data* data = malloc(sizeof(Data));
if (data) {
    data->p_low = &data->arr[0];
    data->p_high = &data->arr[9];
    // 使用...
    free(data);
}

// 或棢查非空
if (data != NULL) {
    printf("%p\n", data->p_low);
}

調試技巧

  • 編譯加 -fsanitize=address -g (GCC/Clang),運行時精確報告空指針解引用位置。
  • GDB: run → 崩潰後 bt 回溯,frame N 查看局部變量。
  • 靜態分析:cppcheck --enable=all、Clang Static Analyzer、Coverity 可編譯期發現。

「指針用前必判空」是 C/C++ 開發者的肌肉記憶,任何結構體指針解引用前務必確認非空。

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