首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言易錯知識點深度解析:標準輸出緩衝、外部聲明陷阱、switch作用域、sizeof副作用與宏陷阱

     編輯:關於C

陷阱1:stdout塊緩衝導致輸出延遲

while (1) {
    fprintf(stdout, "hello-std-out"); // 無\n
    fprintf(stderr, "hello-std-err"); // 無緩衝
    sleep(1);
}

現象:stderr立即顯示,stdout延遲甚至不顯示。

原理:

  • stdout關聯終端時為行緩衝(遇\n刷新),重定向文件時為塊緩衝(滿4K刷新)
  • stderr始終為無緩衝

修正:

fprintf(stdout, "hello-std-out\n");  // 加換行
// 或
fflush(stdout);                      // 手動刷新
// 或
setvbuf(stdout, NULL, _IONBF, 0);    // 設置無緩衝

陷阱2:extern數組聲明類型不匹配

// file1.c
int arr[80];

// file2.c
extern int *arr;  // ❌ 錯誤:指針 ≠ 數組
int main() { arr[1] = 100; } // 運行時崩潰

原因:編譯器按指針生成代碼(間接訪問),實際內存佈局是連續整數(直接訪問)。

正確:extern int arr[]; 或 extern int arr[80];

陷阱3:switch語句跳過變量初始化

int a = 1;
switch (a) {
    int b = 20;  // ⚠️ 編譯警告:unreachable code
    case 1:
        printf("%d", b); // 輸出垃圾值
}

原理:case標號本質是goto目標,直接跳過聲明初始化語句。

修正:用塊作用域包裹:

switch (a) {
    case 1: {
        int b = 20;  // ✅ 安全
        printf("%d", b);
    } break;
}

陷阱4:sizeof不計算副作用表達式

int i = 10;
printf("%d\n", sizeof(i++)); // 輸出4(32位int大小)
printf("%d\n", i);           // 輸出10(i未自增!)

本質:sizeof是編譯期運算符,僅求類型大小,不求值表達式(VLA除外)。

陷阱5:宏參數副作用與註釋吞噬

#define PrintInt(expr) printf("%s : %d\n", #expr, (expr))

int y = 100, *p = malloc(sizeof(int));
*p = 10;
y = y/*p;  // ❌ 誤為 y = y / *p; 實際 /* 開啟註釋!
PrintInt(y); // 輸出100

雙重教訓:

  1. 除法務必加空格:y = y / *p;
  2. 宏參數不要有副作用:PrintInt(i++)展開後i++執行兩次

陷阱6:scanf格式字符串掃描集

char buf[80];
scanf("%[^r]", buf); // 讀取直到字符'r'(不含r)
// 輸入 "Hello, World" → 讀取 "Hello, Wo" (遇r停止)

%[^r]為掃描集:匹配非'r'字符序列,遇'r'、EOF或寬度限制停止。

總結清單

編號核心點關鍵詞
1stdout/stderr緩衝模式差異行緩衝/塊緩衝/無緩衝
2extern數組必須聲明為數組類型指針≠數組
3switch跳過聲明初始化塊作用域包裹
4sizeof不求值無副作用編譯期運算符
5宏參數副作用/註釋吞噬空格分隔/無副作用
6scanf掃描集語法%[^chars]
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved