C 語言給予程序員極大自由,也帶來極多坑。本文梳理 18 類高發錯誤,附錯誤代碼、原因分析、正確寫法與避坑口訣。
a != A
// 錯
int a = 5; printf("%d", A); // A 未聲明
// 正
int a = 5; printf("%d", a);
口訣:常量全大寫,變量全小寫,嚴格區分。
// 錯
float a, b; printf("%d", a % b); // % 僅限整型
// 正
int a, b; printf("%d", a % b);
// 或用 fmod(a, b) 處理浮點
// 錯
char c; c = "a"; // "a" 是字符串(含 \0),占 2 字節
// 正
char c; c = 'a'; // 'a' 是字符,占 1 字節
= vs == 經典誤用
// 錯
if (a = 3) ... // 賦值,值為 3 恆真
// 正
if (a == 3) ... // 比較
// 防禦寫法:if (3 == a) ... 常量在左,誤寫 = 編譯報錯
a = 1
b = 2 // 編譯器視為一條語句,語法錯誤
復合語句最後一條也必須加分號(Pascal 習慣害人)。
// 錯
if (a % 3 == 0); // 分號結束 if,下面語句無條件執行
i++;
// 錯
for (i = 0; i < 5; i++); // 循環體為空,僅跑 5 次空操作
{ scanf(...); printf(...); } // 只執行一次
& 取地址
// 錯
int a, b; scanf("%d%d", a, b);
// 正
scanf("%d%d", &a, &b);
// 數組名/指針本身即地址,不加 &
char str[20]; scanf("%s", str); // 正確
// 格式串 "%d%d" 輸入需用空格/換行分隔,不能用逗號
// 格式串 "%d,%d" 輸入必須帶逗號 "3,4"
// 格式串 "a=%d,b=%d" 輸入必須 "a=3,b=4"
scanf("%c%c%c", &c1, &c2, &c3);
// 輸入 "a b c" → c1='a', c2=' ', c3='b'
// 解決:在格式串前加空格 " %c" 跳過空白
int a = 3; float b = 4.5;
printf("%f%d", a, b); // 運行時輸出亂碼,編譯不報錯
// 必須嚴格對應:%d↔int, %f↔float/double, %p↔指針
// 錯
scanf("%7.2f", &a); // 輸入不支持精度限制
// 正
scanf("%f", &a); // 讀完整數值,輸出時用 %.2f 控制
switch(grade) {
case 'A': printf("85-100");
case 'B': printf("70-84"); // 無 break,A 會印出所有後續
}
// 每個 case 末尾加 break
// while:先判斷後執行,可能 0 次
// do-while:先執行後判斷,至少 1 次
// 輸入 I=11 時,while 不進循環,do-while 執行 1 次
// 錯
int n; scanf("%d", &n); int a[n]; // C99 支持,C++ 不標準,大 n 炸棧
// 正
int *a = malloc(n * sizeof(int)); // 堆分配,用完 free
int a[10] = {1..10};
printf("%d", a[10]); // 越界,未定義行為
// 最大下標是 9
struct { char c; int i; }; // sizeof 可能是 8 而非 5(內存對齊)
// 用 #pragma pack(1) 或排序成員減少填充
// 錯
char str[20]; scanf("%s", &str);
// 正
scanf("%s", str); // 數組名即首地址
// 舊式 K&R 風格錯誤
int max(x, y) int x, y, z; { ... } // z 是形參?還是局部?
// 現代 ANSI 風格
int max(int x, int y) {
int z = x > y ? x : y; // 明確在函數體內定義局部變量
return z;
}
gcc -Wall -Wextra -Werror -pedanticclang --analyze、cppcheck、Coverityi, j, k, a, b, c 流失