本文延續上一篇主題,進一步引入 getchar(),完整比較三大輸入函數在緩衝區處理、白字元策略、回傳值等方面的異同,助你精準選型。
| 特性 | scanf("%s") | gets() / fgets() | getchar() / scanf("%c") |
|---|---|---|---|
| 讀取單位 | 以白字元分隔的「詞」 | 整行(含空格) | 單一字元 |
| 前導白字元 | 自動跳過 | 不跳過(fgets 保留) | 不跳過(%c 直接讀) |
| 結束標誌 | 白字元(留在緩衝區) | \n 或 EOF(gets 丟棄 \n,fgets 保留) | 無(逐字元讀取) |
| 緩衝區殘留 | 留下結束的白字元 | gets 無殘留;fgets 可能留 \n | 無額外殘留 |
| 安全性 | 需指定寬度防溢位 | gets 極不安全;fgets 安全 | 單字元相對安全 |
| 回傳值 | 成功轉換項目數 | 字串指標/NULL | 字元值/EOF |
scanf 留下的 \n 會被後續 gets 讀為空行,或被 getchar/%c 讀為換行字元。解法:scanf 後緊接清理巨集。
char ch1, ch2, ch3, ch4;
scanf("%c", &ch1); // 輸入 'h' + Enter -> ch1='h', 緩衝區留 '\n'
scanf("%c", &ch2); // 直接讀到 '\n'
scanf("%c", &ch3); // 等待輸入...
scanf("%c", &ch4); // ...
若需忽略白字元讀取可見字元,請用 scanf(" %c", &ch)(注意雙引號內有空格)。
char *my_gets(char *buf, int size) {
int c, i = 0;
while (i < size - 1 && (c = getchar()) != EOF && c != '\n')
buf[i++] = c;
buf[i] = '\0';
return (c == EOF && i == 0) ? NULL : buf;
}
此版本可控制長度、正確處理 EOF、不保留 \n,完美替代危險的 gets。
scanf + 寬度限制 + 事後清理緩衝區。fgets(標準、安全、保留 \n 供判斷)。getchar 為基石,構建高層輸入函式。gets、fflush(stdin)、無寬度限制的 scanf("%s")。