Re: [問題] C語言 檔案輸入和輸出

看板C_and_CPP作者 (卡卡獸)時間11年前 (2014/02/23 18:28), 編輯推噓5(505)
留言10則, 5人參與, 最新討論串2/2 (看更多)
※ 引述《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

02/24 02:36, , 1F
補充一下, feof 成立的時間點更詳細地說是讀取失敗之後
02/24 02:36, 1F

02/24 02:37, , 2F
也就是說「還沒讀我哪知道後面沒了?」
02/24 02:37, 2F

02/24 02:38, , 3F
所以 feof 並不會在剛踩進第四圈時成立, 而是在文中所述
02/24 02:38, 3F

02/24 02:38, , 4F
的那個時間點才成立
02/24 02:38, 4F
謝謝 LPH66 補充,修過敘述後應看得出 EOF 時間點是在哪發生的了,感謝。 ※ 編輯: EdisonX 來自: 180.177.74.188 (02/24 02:53)

02/24 22:36, , 5F
請問最後的兩種改法,建議用第一種的原因是?
02/24 22:36, 5F

02/24 23:30, , 6F
主要考慮到 fscanf("%c%c%c",&c1,&c2,&c3)==3 這問題
02/24 23:30, 6F

02/25 10:36, , 7F
我懂了 我現在才知道fscanf的回傳值有這個意義 感謝
02/25 10:36, 7F

02/25 13:22, , 8F
謝謝你~~
02/25 13:22, 8F

02/25 15:54, , 9F
這個可以看man page: RETURN VALUE
02/25 15:54, 9F

02/25 15:54, , 10F
return the number of input items successfully matched
02/25 15:54, 10F
文章代碼(AID): #1J2ZtSL3 (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1J2ZtSL3 (C_and_CPP)