| 函數 | 調用 atexit 註冊函數 | 刷新標準 I/O 緩衝區 | 調用對象析構函數 |
exit() | ✅ 是 | ✅ 是 | ✅ C++ 是 |
_exit() / _Exit() | ❌ 否 | ❌ 否 | ❌ 否 |
return (main) | ✅ 是 | ✅ 是 | ✅ C++ 是 |
abort() | ❌ 否 | ❌ 否 | ❌ 否 |
正確模式
// 正常退出
int main(void) {
atexit(cleanup);
// ...
return 0; // 或 exit(0)
}
// 異常立即終止(如 fork 後子進程)
if (pid == 0) {
_exit(0); // 不執行父進程的 atexit,不衝刷父進程緩衝區
}
第 7 題:memset 參數類型陷阱
原文片段
int func(void *ptr) // 返回 int,實際需 void*
void *memset(void *s, int c, size_t n);
標準簽名解析
void *memset(void *s, int c, size_t n);
// s: 目標內存起始地址
// c: 填充字節值(取低 8 位,即 unsigned char)
// n: 填充字節數
// 返回: s(便於鏈式調用)
常見錯誤
memset(ptr, 0xFF, n) → 實際填充 0xFF(正確)
memset(ptr, 0x100, n) → 低 8 位為 0,填充 0x00(陷阱!)
memset(arr, 1, n) 整型數組 → 每字節置 1,非每元素置 1
正確用法模式
char *ptr = "Linux";
printf("%c\n", *ptr++); // 輸出 L
printf("%c\n", *ptr); // 輸出 i
運算符優先級解析
++(後置)優先級高於 *(解引用)
*ptr++ 等價於 *(ptr++)
- 步驟:① 取當前 ptr 值 ② 解引用得 'L' ③ ptr 指向下一字符
對比:前置遞增
char *ptr = "Linux";
printf("%c\n", *++ptr); // ① ptr+1 ② 解引用得 'i'
printf("%c\n", ++*ptr); // ① 解引用得 'i' ② 字符值+1 得 'j' ③ 寫回內存(常量段崩潰!)
第 9 題:字符串字面量修改導致崩潰
原文代碼
char *ptr = "Linux";
*ptr = 'T'; // 未定義行為:修改只讀內存段
printf("%s\n", ptr);
內存佈局解析
// 字符串字面量存儲在 .rodata 段(只讀)
// ptr 指向 .rodata 區域
// *ptr = 'T' 觸發 SIGSEGV / SIGBUS
// 正確:字符數組在棧上,可修改
char arr[] = "Linux";
arr[0] = 'T'; // 合法
printf("%s\n", arr); // "Tinux"
第 10 題:修改 argv[0] 更改進程名
原文代碼
char buff[100];
memset(buff, 0, sizeof(buff));
strncpy(buff, argv[0], sizeof(buff));
memset(argv[0], 0, strlen(buff)); // 清空原名
strncpy(argv[0], "NewName", 7); // 寫入新名
多重缺陷
strlen(buff) 在 memset 後為 0,實際未清空
argv[0] 指向的內存大小未知,寫入可能越界
- 修改
argv 字符串行為實現定義,不可移植
- 忽略
strncpy 不保證 \0 結尾
跨平台進程名設置
核心教訓總結
| 主題 | 原文錯誤 | 正確認知 |
| 程序退出 | 用 _exit 代替 exit | 正常退出用 exit/return;_exit 僅用於特殊場景 |
| memset 填充值 | 忽略 int 截斷為字節 | 填充值取低 8 位;整型數組慎用非 0/-1 值 |
| 指針遞增 | 混淆 *ptr++ 與 *++ptr | 後置++:先解引用再遞增指針 |
| 字符串字面量 | 嘗試修改 | 只讀內存;需修改請用字符數組 |
| argv 修改 | 不檢查長度、邏輯錯誤 | 不可移植;Linux 用 prctl,Windows 用 API |
C 語言的「坑」大多源於對標準規範的不熟悉。讀懂標準、理解實現、驗證假設,是從「能寫出跑的代碼」到「寫出正確代碼」的必經之路。
- 上一篇文章: 二叉搜索樹葉子節點深度計算:遞歸與迭代實現
- 下一篇文章: 已知有序數組構建最小深度二叉搜索樹
Copyright ©
程式碼之家 All Rights Reserved