輸入 't' 進入 fun() 後,第二個 scanf("%c", &v) 直接讀到殘留的換行符 '\n',導致 switch(v) 進入 default 輸出 "error",無法正常輸入 'u' 或 'h'。
scanf("%c", &m):使用者輸入 t Enter't' '\n'scanf("%c", &m) 讀取 't','\n' 留在緩衝區fun() → scanf("%c", &v)scanf("%c", &v) 立即讀取緩衝區殘留的 '\n'v == '\n',不匹配 'u'/'h',進入 default
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「讀取並丟棄任意數量空白字元,再讀取下一個非空白字元」。
void fun() {
printf("請輸入第二個字母:\n");
char v;
getchar(); // 吃掉一個字元(假設是殘留的 \n)
scanf("%c", &v);
// ...
}
缺點:若緩衝區有多個殘留字元,或無殘留時會吃掉使用者正常輸入。
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 解析:完全掌控輸入,無緩衝區殘留問題%c、%[、%n 前必加空格:" %c"、" %[^\n]"fflush(stdin):非標準、不可移植、行為未定義scanf/fgets 回傳值,處理 EOF/錯誤