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

C語言fgets讀取文件多出\"(null)\":feof判斷邏輯錯誤與正確讀取模式

     編輯:程式設計綜合問答

代碼中`while(!feof(fp)) { printf("%s", fgets(buf, 100, fp)); }`導致最後多輸出`(null)`,原因是**`feof`在讀取失敗後才置位,循環多執行一次**且`fgets`返回`NULL`被`printf("%s")`打印為`(null)`。本文解析原理並給出標準讀取模式。

錯誤流程還原

  1. 最後一行數據讀取成功,`fgets`返回指針,`printf`輸出內容,文件指針到達EOF。
  2. 循環條件`!feof(fp)`仍為真(`feof`尚未置位)。
  3. 再次進入循環,`fgets`嘗試讀取,**遇到EOF返回`NULL`**。
  4. `printf("%s", NULL)` — **未定義行為**,常見輸出`(null)`或崩潰。
  5. 此時`feof(fp)`置位為真,循環結束。

正確讀取模式(三種推薦)

模式一:直接用fgets返回值判斷(最簡、最標準)


while (fgets(buf, sizeof(buf), fp) != NULL) {
    printf("%s", buf); // buf已包含換行符
}

模式二:do-while配合feof(較少用)


do {
    if (fgets(buf, sizeof(buf), fp) == NULL) break;
    printf("%s", buf);
} while (!feof(fp));

模式三:逐行處理帶行號


int line = 0;
while (fgets(buf, sizeof(buf), fp)) {
    printf("%d: %s", ++line, buf);
}

關鍵知識點

  • `fgets`**成功返回緩衝區指針,失敗/EOF返回`NULL`** — 這是唯一可靠的循環條件。
  • `feof`/`ferror`**只在操作後反映狀態**,不能預判下次讀取結果。
  • `fgets`**保留換行符**`\n`(若緩衝區足夠),`printf("%s")`會原樣輸出,**無需額外換行**。
  • `printf("%s", NULL)`是**未定義行為**(C標準),視實現而定(常見`(null)`、崩潰、亂碼)。

代碼修正對比


// ❌ 錯誤
while (!feof(fp)) {
    printf("%s", fgets(buf, 100, fp));
}

// ✅ 正確
while (fgets(buf, 100, fp)) {
    printf("%s", buf);
}

文件寫入端補充

原代碼混用`fputc`、`fputs`、`fwrite`、`fprintf`寫入,且多次手動寫入`\n\r`,導致文件換行符混亂(`\r\n` vs `\n`)。建議統一用`fprintf(fp, "%s\n", str)`或`fputs(str, fp); fputc('\n', fp);`,僅用`\n`,由運行庫處理平台差異。

鐵律:讀文件循環條件永遠用 `fgets/fread/fscanf` 等讀取函數的返回值判斷,絕不單獨用 `feof`。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved