許多 C 語言初學者對 EOF、getchar() 回傳值、feof() 與 ferror() 的關係存在誤解。本文釐清檔案結束判斷的正確邏輯,並詳細說明終端機下 Ctrl+D (Linux) / Ctrl+Z (Windows) 的行為差異。
EOF 是 <stdio.h> 定義的巨集常數,值通常為 -1(int 型別)。getc、fgetc、getchar)無法讀取資料時,回傳 EOF。EOF 的兩種情況:
feof() 與 ferror()?當 fgetc() 回傳 EOF 時,無法單憑回傳值區分「檔案結束」還是「讀取錯誤」。必須配合:
feof(FILE *fp):檢查流的 EOF 標誌是否被設定(僅在嘗試讀取超過檔案末尾時才會設定)。ferror(FILE *fp):檢查流的 錯誤標誌是否被設定。正確判斷模式:
int c;
while ((c = fgetc(fp)) != EOF) {
/* 處理字元 c */
}
if (feof(fp)) {
puts("正常讀取完畢");
} else if (ferror(fp)) {
perror("讀取錯誤");
}
getchar() 必須用 int 接收/* 錯誤寫法 */
char c;
c = getchar(); // 若 getchar() 回傳 EOF (-1),賦值給 char 會截斷/轉換,導致判斷失敗
/* 正確寫法 (K&R C 強調) */
int c;
c = getchar(); // int 能完整容納所有字元值 + EOF (-1)
終端機驅動程式預設處於標準模式(行緩衝,Canonical Mode),輸入以行為單位送達程式。Ctrl+D 的作用取決於當前行已輸入內容:
| 當前行狀態 | 按鍵 | 效果 |
|---|---|---|
| 空行(剛提示輸入) | Ctrl+D 一次 | 產生 EOF,getchar() 回傳 EOF,程式結束讀取。 |
| 已輸入字元,未換行 | Ctrl+D 一次 | 將當前行內容送達程式(相當於換行),不產生 EOF。 |
| 已輸入字元,未換行 | Ctrl+D 連按兩次 | 第一次送達當前行,第二次產生 EOF。 |
| 已輸入字元並按 Enter | Ctrl+D 一次 | 產生 EOF(因為新行是空的)。 |
總結: 只有在 getchar() 等待新的一行輸入時,直接按 Ctrl+D 才相當於檔案結束符。
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF) {
putchar(c);
}
return 0;
}
abc + Ctrl+D → 螢幕顯示 abcabc(第一次 Ctrl+D 送達 "abc",程式印出 "abc";第二次 Ctrl+D 結束)。abc + Enter → 顯示 abc(換行),等待下一行。若需逐字元即時處理(如遊戲、密碼輸入),可切換終端機至 Raw Mode:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int c;
system("stty raw"); // 進入 Raw Mode:逐字元傳送,無回顯、無行編輯
c = getchar(); // 讀取單一字元即返回
putchar(c);
system("stty cooked"); // 恢復標準模式
return 0;
}
此時 getchar() 不需 Enter 或 Ctrl+D 即可返回,Ctrl+D 也不再有特殊含義(會被視為普通字元 0x04)。
EOF 是狀態碼,非資料字元。int 變數接收回傳值。feof()/ferror() 區分正常結束與錯誤。