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

C語言 scanf 跳過輸入?緩衝區殘留換行符導致的經典 Bug 及修復

     編輯:C 語言問答

現象重現

for (;;) {
    printf("Enter a value: ");
    scanf("%lf", &value);      // 第一次正常讀入數字
    // ...
    printf("Continue? (Y/N): ");
    scanf("%c", &answer);      // ❌ 直接讀到上次殘留的 '\n',不等待輸入
    if (tolower(answer) == 'n') break;
}

第二次 scanf("%c") 不會阻塞,因為標準輸入緩衝區還留著上一輪 %lf 讀完後的 \n。

根本原因:stdin 行緩衝 + scanf 不吃掉分隔符

  • %lf 讀取浮點數,遇到非數字字符(如 \n)停止,**將該字符推回緩衝區**。
  • %c 讀取**下一個字符**(包括空白、換行),不跳過任何字符。
  • 結果:殘留的 \n 被 %c 讀走,程序誤以為用戶輸入了空字符。

四種修復方案(按推薦順序)

1. 格式串前加空格(最簡潔、標準)

scanf(" %c", &answer);  // 格式串開頭的空格 = 跳過任意數量空白字符(含 \n、空格、Tab)

✅ 無額外函數調用,可移植,C89 起標準行為。

2. 顯式吞掉換行符

scanf("%lf", &value);
while (getchar() != '\n'); // 循環讀取並丟棄,直到吃掉換行符
scanf("%c", &answer);

⚠️ 若緩衝區已空(如重定向輸入),會陷入死循環,需改為 int c; while ((c=getchar())!='\n' && c!=EOF);。

3. 改用 fgets + sscanf(最穩健)

char line[64];
fgets(line, sizeof(line), stdin);  // 讀整行含 \n
sscanf(line, "%lf", &value);       // 從行緩衝區解析,不影響 stdin

fgets(line, sizeof(line), stdin);
sscanf(line, " %c", &answer);      // 同理

✅ 徹底隔離解析邏輯與輸入流,防溢出、易錯誤處理、適合混合輸入場景。

4. fflush(stdin) —— 非標準、不推薦

fflush(stdin); // 僅 MSVC 支援,GCC/Clang/Linux 下行為未定義(可能無效或崩潰)

❌ 跨平台代碼**嚴禁使用**。

最佳實踐模板

#include <stdio.h>
#include <ctype.h>

int main() {
    double total = 0, value;
    int count = 0;
    char line[64];

    while (1) {
        printf("Enter a value: ");
        if (!fgets(line, sizeof(line), stdin)) break; // EOF 或錯誤
        if (sscanf(line, "%lf", &value) != 1) {
            puts("無效數字,重試。");
            continue;
        }
        total += value;
        count++;

        printf("Continue? (Y/N): ");
        if (!fgets(line, sizeof(line), stdin)) break;
        char ans;
        if (sscanf(line, " %c", &ans) != 1) continue;
        if (tolower(ans) == 'n') break;
    }

    if (count) printf("Average = %.2f\n", total / count);
    return 0;
}

總結

  • scanf 留下的換行符 是 C 語言控制台交互的第一大坑。
  • 方案首選:scanf(" %c", ...) 格式串加空格(只修一字符)。
  • 工程級代碼:統一用 fgets 讀行 + sscanf 解析,徹底規避緩衝區殘留問題。
  • 禁用 fflush(stdin),它不是標準 C。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved