[爆卦]fscanf回傳值是什麼?優點缺點精華區懶人包

為什麼這篇fscanf回傳值鄉民發文收入到精華區:因為在fscanf回傳值這個討論話題中,有許多相關的文章在討論,這篇最有參考價值!作者EdisonX (卡卡獸)看板C_and_CPP標題Re: [問題] C語言 檔案輸入和輸出時間...


※ 引述《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

你可能也想看看

搜尋相關網站