本文精選結構體記憶體佈局、指針 const 語義、動態記憶體管理三大高頻易錯領域,通過代碼實例揭示核心機制。
struct BBB {
long a; // 8 bytes
char c1; // 1 byte
char c2; // 1 byte
long b; // 8 bytes
long c; // 8 bytes
}; // 總大小 32 bytes (64位系統,8字節對齊)
指針運算陷阱:
struct BBB *p = (struct BBB*)0x100000;
p + 1; // 0x100020 (跳過整個結構體,+32)
(unsigned long)p + 1; // 0x100001 (整數運算,+1)
(unsigned long*)p + 1; // 0x100008 (指針運算,+8)
(char*)p + 1; // 0x100001 (字節運算,+1)
核心原則:指針運算步長 = 指向類型大小。
// 聯合體大小 = 最大成員大小(對齊後)
union AAA {
struct { char c1; short sl; char c2; } half; // 6 bytes -> 對齊到 8
short kk; // 2 bytes
}; // 大小 8 bytes (4字節對齊) 或 6 bytes (1字節對齊)
// 結構體大小 = 所有成員大小之和(含填充對齊)
struct BBB {
char ucFirst; // 1
short us; // 2 (偏移2)
char c2; // 1 (偏移4)
short uo; // 2 (偏移6)
}; // 總計 8 bytes (4字節對齊)
缺少 break 導致後續 case 連續執行,可用於合併情況處理,但易引發邏輯錯誤。
const int *p; // 指向常量的指針:不可通過 p 修改值
int const *p; // 同上,別名
int *const p; // 常量指針:p 本身不可修改指向
const int *const p; // 雙重常量:指針與值皆不可修改
口訣:* 左邊修飾值,右邊修飾指針。
錯誤代碼:
void GetMemory(char *p, int len) {
p = (char*)malloc(len); // 修改副本,主函數指針未更新
}
三大錯誤:
正確模式:
void GetMemory(char **p, int len) {
*p = (char*)malloc(len);
}
int main() {
char *p;
GetMemory(&p, 10);
strcpy(p, "bit");
free(p);
p = NULL; // 防野指針
}
掌握這些細節,能避開 C 語言開發中 80% 的隱性 Bug。