• ベストアンサー

fgets関数のEOFの扱い方について

fgets関数のEOFの扱い方って、 ファイルの終わり(EOF)を検出し、かつ配列に1文字も読み取れなかった場合、配列の内容を変化させずに残しNULLを返す。配列に1文字以上読み取れた場合、EOFをバッファに残し配列に'\0' を追加する。その後、EOFを読み取り終了。 であってますか?

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★回答者 No.1 です。追記。 ・回答者 No.2、No.3 さんの通り『EOF』は『EOFコード(^Z)』をバッファに  残すわけではありませんよ。→イメージ的には『あっている』のですよ。あくまで。 ・厳密には、回答者 No.3 さんのアドバイスどおりです。 ・つまり、『fgets』関数で1文字も読み取れなかった場合には、『ファイル終了』  というフラグ情報をセットするのです。→EOFをバッファに残す感じですね。 ・そのため、次に読み込んだ場合に、このフラグ情報を『EOF』として読み取って  終了するわけです。→『fgetc』関数も同じ仕組みです。 ・また、途中でエラーが発生した場合にも『fgets』関数は『NULL』を返します。 ・この場合は、『エラー発生』のフラグ情報をセットしてから『NULL』を返すのです。 ・よって『NULL』が返される多くの場合は、『ファイル終了』ですが、エラーが発生  しても『NULL』が返されます。そこで、『feof』関数や、『ferror』関数でどちらか  判定するわけです。feof(fp) や ferror(fp) で 0 以外が返されたら『ファイル終了』  や『エラー発生』と判別します。→厳密にエラー発生の対策をする場合はね。 ・あと、一度『エラー発生』のフラグがセットされると『fseek』関数などではその  情報はクリアされません。→『clearerr』関数でクリアします。 ・『ファイル終了』情報はファイル・ポインタの位置を変える『fseek』関数などで  その情報がクリアされます。 ・『ファイル終了』、『エラー発生』のフラグ情報などは、それぞれのファイル  ポインタで管理されています。 最後に: ・イメージ的には、最後に『EOFを読み取り終了』という事になります。 ・質問者さんは、プログラムや、テストプログラムを作って動作に疑問を持ったのですね。  そうでないと、『EOF』を検出して、1文字も読み取れなかった場合、配列内容が変化  しない事を推測できませんものね。 ・そこで、最後にアドバイスします。 ・疑問があったら簡単なテスト・プログラムを作ってみて確認することがとても大事ですよ。  動作確認すると『fgets』関数などの仕組みをより理解できますから。 ・以上。おわり。

hiroki239
質問者

お礼

大変、分かりやすかったです。どうもありがとうございます。

その他の回答 (3)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

> 配列に1文字以上読み取れた場合、EOFをバッファに残し配列に'\0' を追加する。 EOFをバッファに残すのではなく、「ファイル終了表示子」をセットすることになります。 ちなみに、fgets関数がNULLを返すのは、EOFに達した場合だけではありません。読み込み途中にエラーが発生した場合にもNULLを返しますが、その場合は「エラー表示子」をセットし、配列の内容は不定になります。

hiroki239
質問者

お礼

非常に、参考になりました

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.2

EOFはキャラクタではないので、EOFがバッファに格納されることはないと思います。 DOS/Windows形式だと^Z がEOFを表すキャラクタとしてファイル中に存在する場合がありえますが、 その場合でも^Z自身がバッファに格納されることはなかったと思います。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.1

★回答 ・はい、あっていますよ。 ・きちんと理解しているようですね。 ・以上。おわり。

hiroki239
質問者

お礼

本当に、ありがとうございます。

関連するQ&A

  • VC++6でfgets関数の変わりになるような関数はあるのでしょうか。

    現在、VC++6を用いて、MFC を使わずにアプリケーションを作っています。 アセンブラ経験はありますが、C言語経験がないので、四苦八苦しています。 今回、 csv形式のファイルを読込んで、配列に格納したいのですが上手くいきません。 c言語の場合は、fopen関数で開いたファイルを、fgets関数で1行づつ読込み、 strtok関数で、処理すれば良いということが分かりました。 ところが、VC++6のCreateFile関数では、ファイルのポインタの変わりに、 クラスのハンドルが返ってくるので、fgets関数は使えないような気がします。 なにかfgets関数の変わりになるような関数はあるのでしょうか。 質問の意味が分かりずらいかと思いますが、適当に汲み取って教えて下さい。 宜しくお願いします。

  • fgetsの使い方

    C言語を今日から始めたじいさんです。 宜しくお願い致します。 メモ帳を使って3行ほどの文字列を入力して、text.txtファイルに保存します。 この文字列を読み込んで、1行ずつ印刷しようとしていますが fgetsでtxtファイルの終了条件がわかりません。 while(fgets(row , sizeof( row ) , fp) != NULL){ printf("%s\n , row); } fclose( fp ); return 0; のようにしているのですが、3行印字処理をして異常終了してしまいます。 本に出ている例をそのまま実行しているのですが、うまくいきません。 txtファイルをダンプしてみると各行の後ろに0d 0aたぶんCR,LFが入っていてNULL=00(?)はありません。テキストファイルの作り方に問題があるのでしょうか? それともfgetsの使い方に誤りがあるのでしょうか?

  • fgetcの返却値 EOFについて

    C言語について質問です。あまり詳しくないので言葉や、説明等間違っているところが あり読みにくいと思います。 fgetc関数の返却値についてのお伺いします。 EOFはファイルの終わり又は、読み込みが失敗すると、返却されるとあります。 ここで、質問なのですが、2つの違いを判断することは可能でしょうか? 私が行った作業は あるファイル内の文字を1文字づつ読み込んで。 文字の種類ごとに指定したbufferferに格納させたいと思っています。 しかし、ファイル内の終端がEOFで終る場合に読み込みエラーの場合と、読み込み終了で 場合分けができない為うまくできません。 #include <stdio.h> #include <ctype.h> char buffer[100]; char *filename="TestFile"; char* main(){ static FILE *fp = NULL; char *p = buffer; int c; if ( fp == NULL ){ if ((fp = fopen( filename, "r" )) == NULL ){ fprintf(stderr,"can not open file %s\n", filename); return ( (char *)NULL ); } } c = fgetc(fp); while(1){ switch(c){ case '\n': case '\0': *p = '\0'; return( buffer); /*以下のcase EOF の時に2通り考えられる*/ case EOF:/*読み込み終了*/ *p = '\0'; return( buffer); /* case EOF:/*読み込みエラー fprintf(stderr, " OPEN _ERROR %s\n", filename); fclose(fp); fp = NULL; return ( (char *)NULL ); */ default: *p = (char)c; p++; } c = fgetc(fp); } } 以上です。 このような場合どうしたらよいのでしょうか?また異なるやり方があればご教授お願いします。 よろしくお願いします。

  • EOF判定されない

    if(fgets(buff, 21, fp) == NULL) {   if(!feof(fp))   {     rtn_code[0] = '8';   }   else   {     rtn_code[0] = '4';   } } -------------------------------------- /入力ファイル/ -------------------------------------- 1行目 AAAAABBBBBCCCCCDDDD[LF] 2行目 EEEEEFFFFFGGGGGHHHH[LF] 3行目 [EOF] -------------------------------------- [LF]=改行文字です。 [EOF]=ファイル終端指示子です。 上記のプログラムは、 1行20バイトある入力ファイルから一行だけgetするサブモジュールの一部です。 3回目にこれを実行した時に、EOFになってrtn_codeが'4'で返ってくる予定なのですが、どうしても非EOFになって'8'が返ってきてしまうのです。 なぜなんでしょうか? そもそも、どうなるとEOF指示子がfpに返ってくるのでしょう?

  • fgetsでバッファ残留文字列を無視して読み込む

    お世話になります。 早速質問させていただきます。 言語はC++です。 ファイルに、以下の文字列があったとします。 ============================ 123456789012 12345678901 1234567890 123456789 ============================ この時、 fgets( str, 10, fp); printf("str (%2d)= %s\n", strlen(str), str); を、EOFになるまで繰り返します。 すると、実施結果は ============================ 123456789 012 123456789 01 123456789 0 123456789 ============================ となります。 これは、fgetsで10というレングスを指定しているために、1行読み込んで、10文字以降の文字列はバッファに残ってしまっているため、 2度目のfgetsで、10文字以降の文字列が読み込まれ、書き出されているものと思われます。 この時、fgetsで1行読み込んだ後、バッファに残った文字列を無視し、2度目のfgetsで、2行目を読み込むにはどうしたらよいでしょうか? 有識者の方、ご教授ください。よろしくお願いします。

  • fgetsで2行目から文字化け

    fgetsでファイルを一行ずつ読み込みたいのですが、二行目以降が文字化けしてしまいます。 ******* ソース ******* #include <windows.h> #include <stdio.h> FILE *fp; if ((fp = fopen("textlist.txt", "r")) == NULL){ MessageBox(NULL, TEXT("ファイルを開けません"), NULL, NULL); exit (1); } while (1) { TCHAR buf[128] = {0}; if (fgets(buf, sizeof(buf), fp) == NULL) break; MessageBox(NULL,buf,NULL,NULL); } fclose(fp); ***** textlist.txt ***** あいうえお かきくけこ さしすせそ メッセージボックスの一回目は正しく"あいうえお"と表示されますが、二回目・三回目は文字化けしています。 最終的に一行ずつ分けて配列に入れたいので、fgetsで出来たらと思っています。 よろしくお願いします。

  • fgets の失敗時、再読み込み開始位置は?

    こんにちは。 fgets の失敗時、再読み込み開始位置はどこになるのでしょうか? 例えば、以下点線内のファイルを読み込み、bを読み込めずに失敗した場合 再度 fgets を発行(以下★)した場合、得られる文字列はどれでしょうか? (EOFまで読み込み NULL で返却されることは考えないとします) ----- a b c ----- if( fgets( line, 100, stream ) == NULL)  fgets( line, 100, stream ) ★ 元々CStdioFile クラスの ReadString メソッドで CFileException がスローされた場合の再読み込み処理を 調べていたのですが、ReadString メソッド内部では fgets をコールしていたので質問させていただきました。 よろしくお願いします。 Windows XP VC++6.0

  • 続・EOF判定されない

    前回「EOF判定されない」で回答、アドバイスしていただいた a-kumaさん、Haizyさん、inthefloiさん、anisolさん、leaz024さん、cherry-moonさん 本当にありがとうございました。頂いたアドバイスを試行してみましたが、なぜか、ダメでした。(T-T) 環境が悪いのかもしれませんね。 あれから、feof関数を使わずにファイルの終わりを算出して判定するなどの方法を試みましたが、EOF判定だけのために妙に複雑になってしまい、自分でも納得がいかなかったので、再度こちらで皆さんの意見をもらおうと投稿させてもらいました。 今回は質問の仕方を変えて、モジュールの仕様を挙げますので、それから「自分ならこうする」というようなお答えを頂けたらと思っています。 feof関数を使用しても、その他の方法でもなんでもアリです。(^^) 「ファイル一行入力モジュール」(仕様) 1.このモジュールは実行されると「inputfile.txt」から一行だけ(改行まで)読み込み、終了します。次に実行された時は、その次の行を読み込みます。 2.ファイルの終端に達したら、リターンコードに'4'を設定し、終了する。 以上これだけ。(^^; 「inputfile.txt」(仕様) インプットファイルは、テキストファイルで、一行30バイトの文字列を格納しています。ファイルの総バイト数は不定です。 文字コードは「Shift-JIS」「改行=CR+LF」、ファイルの最後にEOF制御文字を設定しています。 「インプットファイルの内容」  1行目 AAAAAAAAAABBBBBBBBBBCCCCCCCCC[改行文字]  2行目 DDDDDDDDDDEEEEEEEEEEFFFFFFFFF[改行文字]           ・           ・           ・ n-1行目 XXXXXXXXXXYYYYYYYYYYZZZZZZZZZ[改行文字]  n行目 [EOF] 「ここはこうしたらいいんじゃないかな?」的な事でかまいませんので、是非みなさんの意見を聞かせてください。

  • fgets で値が取得できない

    fopen , fgets に関して質問させてください。 現在「readme」というファイルを UTF-8 にて開こうとしております。 fopen でファイルは開けているようなのですが、fgets を呼び出した際に以下の様なメッセージが出て異常終了してしまいます。 『Microsoft Visual Studio C ランタイム ライブラリは Sample.exe に致命的なエラーを検出しました。 [中断] をクリックしてプログラムをデバッグするか、または [続行] をクリックしてプログラムを終了してください。』 UTF-8 を指定しない場合は上手く動いているようです。 UTF-8 の時は特殊な取り出し方をしなければならないのでしょうか? Visual C++ 2008 Express Edhition の デバックモードで動かしています。 ****************************** 1 : FILE *file1; 2 : char s[256]; 3 : 4 : file1 = fopen( "C:\\readme", "r, ccs=UTF-8"); 5 : while (fgets(s, 256, file1) != NULL) 6 : { 7 : printf("%s", s); 8 : } ******************************

  • ファイル読み込み EOF 判定

    数字の羅列した単純なテキストファイルを読み込ませたいのですが、 以下のようにすると、途中で改行などで一行あけた場合、そこで読むのを ストップしてしまいます。 if (fgets(buf, sizeof(buf), fp) == NULL) { 改行にくじけることなく、ファイルの最後まで読み込ませるにはどうしたら いいのでしょうか。 ちなみに、以下のようにやると、   while(getc(fp) != EOF){ こんどは改行をものともせず、ファイルのお終いまで読んでくれるのですが、 2バイト文字(頭一文字が化ける)、のっけ一行目に数値(10桁)を置くと 一文字かけて9桁になってしまいます。 2行目以降はちゃんと10桁です。(一行目に改行をいれて、2行目以降に書くと大丈夫のようです。変) 簡単なようで、つまってます。どうかよろしくお願いします。

専門家に質問してみよう