有網友在論壇發帖求助,希望大神詳細解釋一段C語言代碼的功能:該代碼旨在打開指定路徑的文本文件,並統計文件中的總行數。原帖代碼結構清晰,但缺乏詳細註釋,初學者難以理解文件指針移動、字符讀取及行數判斷的具體邏輯。
int lines() {
FILE *fp; // 定義文件指針
int line = 0; // 行數計數器
int filesize = 0; // 文件大小(字節數)
char ch = 0; // 暫存讀取的單個字符
// 嘗試以只讀模式打開文件,若失敗(文件不存在)則以寫入模式創建
if ((fp = fopen("c:\\filename.txt", "r")) == NULL)
fp = fopen("c:\\filename.txt", "w");
// 將文件指針移至文件末尾
fseek(fp, 0, SEEK_END);
// 獲取當前指針位置,即文件總大小
filesize = ftell(fp);
// 將指針重置至文件開頭,準備逐字符讀取
fseek(fp, 0, SEEK_SET);
// 當文件大小計數器大於 0 時循環
while (filesize) {
ch = fgetc(fp); // 讀取一個字符
if (ch == 0x0a) { // 0x0a 為換行符(LF)的 ASCII 碼
line = line + 1; // 遇到換行符,行數加 1
}
filesize--; // 剩餘未讀字節數減 1
}
fclose(fp); // 關閉文件
return line; // 返回總行數
}
fopen("c:\\filename.txt", "r") 嘗試以只讀方式打開文件。注意路徑中的雙反斜杠 \\ 是 C 語言中轉義單個反斜杠的寫法。若返回 NULL 表示打開失敗(通常是文件不存在),隨後以 "w" 模式創建新文件。這裡有一個潛在邏輯缺陷:若文件不存在,創建後文件為空,後續統計行數將返回 0,這或許是預期行為,但需開發者確認。
fseek/ftellfseek(fp, 0, SEEK_END):將指針移至文件末尾(偏移 0 字節)。ftell(fp):返回當前指針位置,此時即為文件總大小(字節數)。fseek(fp, 0, SEEK_SET):將指針移回文件開頭(偏移 0 字節),為後續 fgetc 逐字符讀取做準備。fgetc(fp) 每次從當前指針位置讀取一字符並自動後移指針。代碼通過 ch == 0x0a 判斷是否為換行符(Linux/Unix 風格 \n)。注意:Windows 文本文件換行通常為 \r\n (0x0d 0x0a),若文件為 Windows 格式,此代碼仍能正確統計行數,因為只檢測 0x0a;但若文件僅含 \r (Mac OS 9 及更早風格),則會漏統計。
利用 filesize 作為計數器,每讀一字符遞減,歸零時代表文件讀完,循環結束。這避免了使用 feof() 可能帶來的「多讀一次」問題。
fopen 失敗時僅創建文件,未判斷創建是否成功;建議在創建後再次檢查 fp 是否為 NULL。\r\n、\n、\r 三種風格,可引入狀態機或檢測 ch == '\n' || ch == '\r' 並處理連續 \r\n 避免重複計數。fclose 執行,可結合 goto 錯誤處理標籤或 C99 變長數組特性簡化邏輯。該函數展示了 C 語言底層文件操作的經典流程:打開 → 定位末尾獲取大小 → 定位開頭 → 逐字符讀取並統計特定標記 → 關閉文件 → 返回結果。理解文件指針移動、fgetc 行為及換行符編碼差異,是掌握 C 語言文件處理的關鍵基石。