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

C語言 scanf 緩衝區殘留換行符導致 switch-case 輸入跳過問題

     編輯:C 語言問答

問題現象

輸入 't' 進入 fun() 後,第二個 scanf("%c", &v) 直接讀到殘留的換行符 '\n',導致 switch(v) 進入 default 輸出 "error",無法正常輸入 'u' 或 'h'。

根本原因:輸入緩衝區機制

  1. 主程式 scanf("%c", &m):使用者輸入 t Enter
  2. 緩衝區內容:'t' '\n'
  3. scanf("%c", &m) 讀取 't','\n' 留在緩衝區
  4. 呼叫 fun() → scanf("%c", &v)
  5. scanf("%c", &v) 立即讀取緩衝區殘留的 '\n'
  6. v == '\n',不匹配 'u'/'h',進入 default

三種解決方案

方法一:scanf 格式字串前加空格(推薦,最簡潔)


void fun() {
    printf("請輸入第二個字母:\n");
    char v;
    scanf(" %c", &v);  // 關鍵:%c 前加空格,跳過所有空白字元(含 \n, \r, space, tab)
    switch(v) {
        case 'u': printf("星期二\n"); break;
        case 'h': printf("星期四\n"); break;
        default: printf("error\n");
    }
}

原理:%c 前的空格指示 scanf「讀取並丟棄任意數量空白字元,再讀取下一個非空白字元」。

方法二:前置 getchar() 吃掉殘留換行符


void fun() {
    printf("請輸入第二個字母:\n");
    char v;
    getchar();  // 吃掉一個字元(假設是殘留的 \n)
    scanf("%c", &v);
    // ...
}

缺點:若緩衝區有多個殘留字元,或無殘留時會吃掉使用者正常輸入。

方法三:fflush(stdin)(非標準,僅 Windows/MSVC 支援)


void fun() {
    fflush(stdin);  // 清空輸入緩衝區(C 標準未定義行為,Linux 無效)
    scanf("%c", &v);
    // ...
}

警告:不可移植,C 標準規定 fflush 僅適用於輸出流,輸入流行為未定義。

完整修正版主程式


#include 

void fun();

int main() {
    char m;
    int i;
    char *day[7] = {"monday","tuesday","wednesday","thursday","friday","saturday","sunday"};

    for(i = 0; i < 7; i++)
        printf("%s ", day[i]);
    printf("\n請輸入首字母: ");

    scanf(" %c", &m);  // 主程式也加空格,良好習慣

    switch(m) {
        case 'm': printf("星期一\n"); break;
        case 'w': printf("星期三\n"); break;
        case 'f': printf("星期五\n"); break;
        case 't': fun(); break;
        default: printf("error\n");
    }
    return 0;
}

void fun() {
    printf("請輸入第二個字母:\n");
    char v;
    scanf(" %c", &v);  // 關鍵修正
    switch(v) {
        case 'u': printf("星期二\n"); break;
        case 'h': printf("星期四\n"); break;
        default: printf("error\n");
    }
}

執行驗證

monday tuesday wednesday thursday friday saturday sunday 
請輸入首字母: t
請輸入第二個字母:
u
星期二

延伸:更健壯的輸入處理模式


// 讀取一行完整輸入,再解析,完全避開緩衝區殘留問題
char line[100];
if (fgets(line, sizeof(line), stdin)) {
    char m = line[0];  // 取第一個非空白字元需自行跳過
    // 或用 sscanf(line, " %c", &m);
}

關鍵知識點總結

現象原因標準解法
scanf("%c") 讀到 \n上次輸入留下換行符在緩衝區scanf(" %c", &c) 格式字串加空格
scanf("%d") 後 scanf("%c") 讀到 \n%d 讀完數字停在 \n 前scanf(" %c", &c) 或中間加 getchar()
fgets 讀到空行上次 scanf 留下 \n,fgets 讀取空行先 getchar() 吃掉 \n,或改用 fgets 統一讀行再解析

最佳實務建議

  • 統一使用 fgets 讀行 + sscanf/strtok 解析:完全掌控輸入,無緩衝區殘留問題
  • 若用 scanf,%c、%[、%n 前必加空格:" %c"、" %[^\n]"
  • 不要用 fflush(stdin):非標準、不可移植、行為未定義
  • 輸入驗證:檢查 scanf/fgets 回傳值,處理 EOF/錯誤
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved