剛學 C 語言時,程式跑不通、跑出錯誤結果是常態。盲目修改代碼往往越改越錯。本文將常見錯誤分為三大類——邏輯錯誤、演算法錯誤、低級語法錯誤,並提供系統化排查步驟與經典案例,助你建立高效除錯思維。
現象:輸出結果隨機、不可預期。
int main() {
int x = 5, y, z; // y 未賦值!
z = x * y; // y 是亂碼(棧上殘留值)
printf("%d", z);
}
對策:宣告即初始化(int y = 0;),或在首次使用前確保賦值。開啟編譯器警告(-Wall -Wextra)可捕獲大部分此類問題。
= 與比較 == 混淆現象:if (a = 5) 永真,導致分支錯誤。
if (a = 5) { printf("a等於5"); } // 實際是賦值,a 變 5,條件為真
對策:養成「常量在左」習慣:if (5 == a),若誤寫成 5 = a 編譯器直接報錯。或使用靜態分析工具(Cppcheck、Clang Static Analyzer)。
switch 缺少 break 導致貫穿。do { ... } while(); 結尾漏寫分號。正確演算法(需暫存變數):
int a = 5, b = 10, temp;
temp = a;
a = b;
b = temp;
錯誤寫法:順序顛倒 a = b; b = a; 導致兩者皆變為原 b 值。
對策:在動筆寫代碼前,先在紙上推演演算法步驟;關鍵邏輯寫成獨立函數並編寫單元測試。
;。scanf("%d", a) 缺少取址符 &(應為 &a),導致段錯誤。%d 對應 float)。對策:
gcc -Wall -Werror -std=c11 將警告視為錯誤。valgrind 檢測記憶體錯誤(未初始化讀取、越界、洩漏)。assert() 驗證前置條件。gdb 斷點單步、觀察變數變化;或插入 printf 關鍵路徑日誌。| 工具 | 用途 |
|---|---|
| GDB / LLDB | 互動式除錯器,斷點、單步、堆疊追蹤 |
| Valgrind | 記憶體錯誤檢測(越界、洩漏、未初始化) |
| AddressSanitizer (ASan) | 編譯器內建記憶體檢測(-fsanitize=address) |
| Cppcheck | 靜態分析,發現邏輯與風格問題 |
除錯核心心法:先理解程式「應該」做什麼,再看它「實際」做了什麼。 不要憑直覺亂改,要用證據定位錯誤源頭。