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

C/C++ feof() 陷阱:二進制文件讀取導致多讀一次的經典問題

     編輯:程式設計綜合問答

問題代碼

while (!feof(f1)) {
    fread(&a, sizeof(a), 1, f1);
    printf("%d\t", i++);
}

預期讀取 10000 筆記錄,實際輸出 25 次(或多讀一次)。

根本原因

feof() 只在「讀操作嘗試讀取超過文件末尾」後才返回真,而非在到達末尾時即返回真。

流程:

  1. 讀取第 10000 筆 → 成功,文件指針指向 EOF
  2. feof(f1) 仍為假(因為上次讀成功)
  3. 進入循環,第 10001 次 fread → 返回 0(讀取 0 項),不修改 a
  4. feof(f1) 變為真
  5. 循環結束,但已多執行一次 printf

正確寫法

方案一:以 fread 返回值為循環條件(推薦)

while (fread(&a, sizeof(a), 1, f1) == 1) {
    printf("%d\t", i++);
}

方案二:先讀後判斷

while (true) {
    size_t ret = fread(&a, sizeof(a), 1, f1);
    if (ret != 1) break;
    printf("%d\t", i++);
}

方案三:文本模式下配合 fgets/feof(不推薦用於二進制)

// 僅適用文本文件
while (fgets(buf, sizeof(buf), f1)) {
    // 處理
}

深度解析

  • 文本模式:Windows 下 \r\n → \n 轉換,feof 行為相對可預期
  • 二進制模式(代碼中 fopen("in.dat","w") 默認文本,但 fwrite 寫結構體實為二進制):feof 極不可靠,因任意位元組模式可能匹配 EOF 標記
  • 最佳實踐:永遠使用讀取函數的返回值判斷循環,不要依賴 feof()/ferror() 作為循環條件

補充:C++ iostream 正確讀法

while (fin.read(reinterpret_cast<char*>(&a), sizeof(a))) {
    cout << i++ << '\t';
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved