for (; i != 234; ) {
printf("數字");
scanf("%d", &a[k]);
printf("字母");
scanf("%d", &i); // 💣 期望輸入字母,卻用 %d
k++;
}
scanf("%d", &i) 期望讀取整數,跳過空白字符 (空格、換行、Tab)。a 並按 Enter,緩衝區剩 "a\n"。%d 發現首字符 'a' 非數字,**匹配失敗**,不消耗任何字符**,i 值不變**,緩衝區仍殘留 "a\n"。i != 234 依然成立,進入下一次迭代。scanf("%d", &i),面對同樣的 "a\n",再次匹配失敗……**無限循環**。| 方案 | 代碼片段 | 優點 | 缺點 |
|---|---|---|---|
| 改用字符讀取 | scanf(" %c", &ch); (注意前導空格吃掉換行) | 簡單、直接讀字符 | 需自行驗證是否為數字/字母 |
| 讀整行再解析 | fgets(buf, sizeof(buf), stdin); sscanf(buf, "%d", &i); | 完全控制輸入、易於錯誤恢復 | 稍顯繁瑣 |
| 檢查 scanf 返回值 | if (scanf("%d", &i) != 1) { /* 清理緩衝區 */ while (getchar() != '\n'); } | 標準做法、健壯 | 需記住清理緩衝區模式 |
int putin(int a[]) {
int k = 0;
char ch;
for (; ch != 'k'; ) { // ⚠️ ch 未初始化!
printf("數字\n");
scanf("%d", &a[k]);
printf("字母\n");
scanf(" %c", &ch); // 前導空格吃掉殘留換行
k++;
}
return k;
}
三個關鍵修正:
char ch = 0; 初始化,避免首次判斷用到垃圾值。scanf(" %c", &ch) 前導空格自動跳過空白字符 (含上一行殘留的 \n)。printf("數字\\n") 加換行,提示與輸入分行,體驗更好。int x;
while (1) {
printf("請輸入整數: ");
int ret = scanf("%d", &x);
if (ret == 1) break; // 成功讀到 1 個整數
if (ret == EOF) exit(1); // Ctrl+D / Ctrl+Z 結束
// ret == 0:匹配失敗,清理緩衝區
while (getchar() != '\n'); // 吃掉本行剩餘字符
printf("輸入無效,請重試。\n");
}
核心心法
1.scanf返回 成功匹配並賦值的項目數,而非讀取字符數。
2. 匹配失敗不消耗輸入**,必須手動清理緩衝區。
3. 生產級代碼 永不直接信任 scanf,一律用fgets+sscanf/strtol組合。
4.%c不會自動跳過空白,需在格式串加空格" %c"。