錯誤程式碼
struct person { int age; char name; };
struct student { struct person abc; int id; };
struct student *f1; // 僅宣告指標,未分配記憶體!
int main()
{
f1->id = 20; // 段錯誤:寫入隨機位址
f1->abc.age = 20; // 未定義行為
return 0;
}
錯誤分析
f1 是野指標,值為隨機堆疊殘留資料
- 解參考
f1->id 相當於 *(f1 + offset),存取非法記憶體
- 作業系統偵測到非法存取,送出
SIGSEGV,程式終止
正確程式碼
int main()
{
struct student *f1 = malloc(sizeof(struct student));
if (!f1) { perror("malloc"); return 1; }
f1->id = 20;
printf("%d\n", f1->id);
f1->abc.age = 20;
printf("%d\n", f1->abc.age);
free(f1); // 釋放記憶體,良好習慣
f1 = NULL; // 避免懸空指標
return 0;
}
記憶體分配檢查清單
| 情境 | 正確做法 |
| 結構體指標 | malloc(sizeof(Struct)) |
| 陣列指標 | malloc(n * sizeof(Type)) |
| 字串 | malloc(strlen(src) + 1) |
| 嵌套結構體 | 外層 malloc 即可,內層隨外層分配 |
| 釋放 | 每個 malloc 對應一個 free,釋放後置 NULL |
進階技巧:柔性陣列成員 (C99)
struct buffer {
size_t len;
char data[]; // 柔性陣列,不佔結構體大小
};
struct buffer *buf = malloc(sizeof(struct buffer) + 100);
buf->len = 100;
// buf->data 可直接使用 100 bytes
free(buf); // 一次釋放全部
除錯工具
valgrind --leak-check=full ./prog:偵測記憶體洩漏、非法存取
gcc -fsanitize=address -g:AddressSanitizer 編譯期插桩
malloc.h 的 mtrace():追蹤 malloc/free 呼叫