看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《sheankuo (筱釵)》之銘言: 恕刪 : 最後附上程式碼~ : http://codepad.org/ePCwQr0f 新手 Q&A 問題,不過剛好我沒找到版上文章有細講,拋磚引玉。 fp1=fopen("1.txt","r"); fp2=fopen("2.txt","w"); do { fscanf(fp1,"%c",&c); fprintf(fp2,"%c",c); } while(!feof(fp1)); 假設 1.txt 內容是只有三個字元 abc 的時候,它的整個動作是這樣的 ------------- 第 1 次讀取 --------------- 1.txt 2.txt fscanf(fp1, "%c", &c); abc fprintf(fp2, "%c", c); a fp1 還沒讀到尾,所以 !feof(fp1) 成立,繼續跑下一次。 ------------- 第 2 次讀取 --------------- 1.txt 2.txt fscanf(fp1, "%c", &c); abc fprintf(fp2, "%c", c); ab fp1 還沒讀到尾,所以 !feof(fp1) 成立,繼續跑下一次。 ------------- 第 3 次讀取 --------------- < 請注意這裡開始是關鍵 > 1.txt 2.txt fscanf(fp1, "%c", &c); abc fprintf(fp2, "%c", c); abc 好了,到這裡其實 fp1 雖然已經讀完最後一個字元了,但實際上 fp1 的位置還是若在 最後一個 character 上面,所以 !feof(fp1) 還是成立的,接著還會再繼續跑下一次 ------------- 第 4 次讀取 --------------- 關鍵是在於第四次讀取會發生什麼事。 原本的檔案指標移動會是 abc abc abc abc - - - - 所謂的 eof 發生的時候指的是,它已經指到不能再指了,然後還要再去 "硬讀", 硬讀的結果並不會再吐任何字元給你,只會由某些函式或傳回值告訴你,現在已經 沒辦法讀了。也就是上述的第四種情況下,再用 fscanf / fgetc 的時候才會使 EOF 生效。再繼續想一下會導致程式裡有什麼效應。 1.txt fscanf(fp1, "%c", &c); abc_ ----> 移到檔案結尾了,但實際上這裡的 c 不會 等於 EOF ,而是 fscanf 讀到底了才知道 原來已經到了 EOF , 而 變數 c 還是 維持上一個值 - 'c' 2.txt fprintf(fp2, "%c", c); abcc ---> 這裡的 c 就是因為 fscanf 遇到 EOF 之後, 並沒有把 char c 清掉, 所以維持上一個字元繼續 輸出。 while( !feof(fp1) ) 這時候才變成 false,跳出 loop 回圈,所以這種寫法做文字檔 複制,永遠會有多一個字元在最後面。 ----------- 修改 ------------------ 一種修改方式,你可以在 do-while 裡面多判斷,在做 fscanf 結束後是不是到了 feof ,這是你原本架構下的修改。 do { fscanf(fp1, "%c", &c); if(feof(fp1)) break; fprintf(fp1, "%c", c); } while(!feof(fp1)); 但其實這修改沒什麼太大意義,feof 這函式目前幾乎沒什麼人在用, 大多都是直接去判斷 fscanf 傳回值做決定 (fscanf,fgets,fgetc 都有傳回值)。 fscanf 傳回值代表 "成功匹配的引數個數",上面只有一個變數做配對,所以 成功的話是傳回 1。若是 fscanf(fp1, "%c%c%c",&c1,&c2,&c3); 三個都成功 的話傳回 3。然後如果遇到檔案讀完的話,會傳回 EOF (EOF 通常 是被定義成 -1), 於是有兩種改法 while(fscanf(fp1, "%c", &c)==1){ // 我比較建議用這個 fprintf(fp2, "%c", c); } while(fscanf(fp1, "%c", &c)!=EOF){ fprintf(fp2, "%c", c); } 簡單的說,掌握一個原則:沒事就不要用 feof 來做判斷檔案是不是已讀取完畢 ; c++ 的話也盡不要用 ifstream::eof 相關函式做判斷, 可以的話都盡可能用讀檔、寫檔的傳回值,來判定檔案是否正常讀寫。 以上供參考,若有誤或其他補充歡迎不吝提出。 -- ~ 這輩子與神手無緣 我只好當神獸了 ~ 卡卡獸 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 180.177.74.188
LPH66:補充一下, feof 成立的時間點更詳細地說是讀取失敗之後 02/24 02:36
LPH66:也就是說「還沒讀我哪知道後面沒了?」 02/24 02:37
LPH66:所以 feof 並不會在剛踩進第四圈時成立, 而是在文中所述 02/24 02:38
LPH66:的那個時間點才成立 02/24 02:38
謝謝 LPH66 補充,修過敘述後應看得出 EOF 時間點是在哪發生的了,感謝。 ※ 編輯: EdisonX 來自: 180.177.74.188 (02/24 02:53)
twooo333:請問最後的兩種改法,建議用第一種的原因是? 02/24 22:36
EdisonX:主要考慮到 fscanf("%c%c%c",&c1,&c2,&c3)==3 這問題 02/24 23:30
twooo333:我懂了 我現在才知道fscanf的回傳值有這個意義 感謝 02/25 10:36
sheankuo:謝謝你~~ 02/25 13:22
lc85301:這個可以看man page: RETURN VALUE 02/25 15:54
lc85301:return the number of input items successfully matched 02/25 15:54