#include#include struct Person { int age; char name; }; struct Student { struct Person abc; int id; }; struct Student *f1; // 全域指標,未初始化 (靜態儲存區預設為 NULL) int main(void) { f1->id = 20; // ❌ 段錯誤:解參考野指標/NULL printf("%d\n", f1->id); f1->abc.age = 20; // 同樣崩潰 printf("%d\n", f1->abc.age); return 0; }
錯誤現象:編譯通過,執行時直接崩潰 (Segmentation Fault / Access Violation)。初學者常困惑:「語法都對啊,為什麼不行?」
struct Student *f1; 只是宣告一個**指標變數** (8 位元組/64位系統),儲存的是**位址**。NULL (0 位址),區域指標則是**不定值 (垃圾位址)**。f1->id 等同 (*f1).id,嘗試存取位址 0 (或垃圾位址) 的記憶體 → **作業系統保護機制攔截,進程終止**。#include#include struct Person { int age; char name; }; struct Student { struct Person abc; int id; }; int main(void) { // 1️⃣ 配置記憶體:向堆疊申請 sizeof(struct Student) 位元組 struct Student *f1 = malloc(sizeof(struct Student)); if (!f1) { perror("malloc 失敗"); return 1; } // 必須檢查 NULL // 2️⃣ 使用記憶體:現在 f1 指向有效可寫入區域 f1->id = 20; printf("%d\n", f1->id); // 20 f1->abc.age = 20; printf("%d\n", f1->abc.age); // 20 // 3️⃣ 釋放記憶體:歸還給堆疊,避免記憶體洩漏 free(f1); f1 = NULL; // 防懸空指標 (好習慣) return 0; }
執行 malloc 後: 堆疊 (Heap) 棧 (Stack - main) +---------------------+ +---------------------+ | struct Student | ←────── | f1 (指標) 0x7f... | | id: 20 | | | | abc.age: 20 | +---------------------+ | abc.name: ? | +---------------------+
| 錯誤程式碼 | 問題 | 修正 |
|---|---|---|
int *p; *p = 10; | 野指標解參考 | int *p = malloc(sizeof(int)); |
char *s; scanf("%s", s); | 未配置緩衝區 | char s[100]; 或 malloc(100) |
Node *head; head->next = NULL; | 鏈表頭節點未 malloc | head = malloc(sizeof(Node)); |
free(p); p->val = 0; | 釋放後使用 (UAF) | free(p); p = NULL; |
p = malloc(10); p = malloc(20); | 記憶體洩漏 (第一塊失聯) | 先 free(p) 再重新配置 |
若結構體包含柔性陣列,配置大小需加上陣列長度:
struct Buffer { size_t len; char data[]; }; // 柔性陣列
struct Buffer *buf = malloc(sizeof(struct Buffer) + 100); // 額外 100 位元組
buf->len = 100;
// 使用 buf->data[0..99]
free(buf);
valgrind --leak-check=full ./prog 偵測洩漏、非法存取、未初始化值-fsanitize=address -g,執行時即時回報錯誤位置Type *p = NULL; 或 Type *p = malloc(...);malloc/calloc/realloc 對應一個 freefree(p); p = NULL; 防止 Double Free / UAFfgets、scanf("%99s", buf) 指定寬度clang --analyze、cppcheck、Coverity指標是 C 語言的靈魂,也是最大的坑源。**指標變數本身不包含資料,只包含位址;位址必須指向有效、已配置、未釋放的記憶體區域,解參考才安全**。養成「宣告→配置→檢查→使用→釋放→歸零」的肌肉記憶,能消除 99% 的指標相關崩潰。