• 締切済み

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に返ってくるのでしょう?

みんなの回答

  • a-kuma
  • ベストアンサー率50% (1122/2211)
回答No.8

解決したのかな~ 状況は想像するしかないのですが、多分、No.4 の leaz024 さんの回答で解決する 問題だと思います。 > [EOF]=ファイル終端指示子です。 なんて書いているあたりが、Windows(MS-DOS を引きずっている)っぽい。 で、 > そもそも、どうなるとEOF指示子がfpに返ってくるのでしょう? についてなんですが、直前の読み込み処理(fgets に限らず fgetc や fread でも 良い)において、既に EOF が検出されていた場合に、ゼロ以外を、そうじゃないとき にはゼロを返します。 読み込み関数が正常以外を返してきたときに、EOF なのか Error なのかを判別する ために存在します(ferror の裏)。あなたの考え方であってますよ。

  • Haizy
  • ベストアンサー率40% (404/988)
回答No.7

HAIZY@のーみそ・とろ~んだった(過去形)です。 #3 について はい、逆です。間違えました。ゴメンナサイ。 今回の教訓: 本職(コンピュータ関係)がトラブってるの時は、回答しない方が良い(笑) 混乱を招き、本当に申し訳ございません。 ●デバックのツールで解析してみましょう。 トレース と ブレークポイントを駆使し、「監視式」で各変数に何が入っているのか、監視してみる。 if(feof(fp)) を式評価してみる。 if (gets(buff, 21, fp)) buff の最大容量を考慮した上で、21 を大きくしてみる。 結果どうなるか。 buffの値を監視式で見てみる。(16進表示が良い。) 単純なデバッグ作業です。 「わたしなら、こうします」と言う感じです。 参考になれば。

noname#30727
noname#30727
回答No.6

leaz024さんが言われている事は、その通りだと思うのですが、それ以前に、fgetsに問題があります。 fgetsの戻り値がNULLになるのは、ファイルの終端以降を読み込もうとしたか、何らかのエラーが発生した場合です。 特別なエラー処理が必要ないのでしたら、まずはファイルオープンで"rb"を"rt"にして、 if (gets(buff, 21, fp)) { rtn_code[0] = '8'; } else { rtn_code[0] = '4'; } というようにされてはどうでしょうか? それから、EOFがファイルの終端に付加されるかどうかはテキストエディタ及びオプションしだいです。

  • anisol
  • ベストアンサー率48% (146/301)
回答No.5

leaz024さんに加えて、ちょっと指摘しておきます。[EOF]のコードは正しいですか?MS-DOSでは[EOF]のコードは1AHですが、stdio.hではFFHと定義されているようです。1AHになっているか確認してみてください。 (なお、私はC言語はほとんどわからないのですが、興味があったので昔のパソコンで調べてみました。的外れなアドバイスだったら無視してください)

  • leaz024
  • ベストアンサー率75% (398/526)
回答No.4

何やらfeofで揉めてますが、質問にある使い方に問題はないように思えます。 ところで改行文字[LF]と書いてありますが、これは確実ですか? Cでは改行を[\n]という一文字で片付けてしまいますが、単なるWindowsのテキストファイルだと、実際には[CR][LF]という2バイトになっています。 テキストモードなら、[CR][LF]→[\n]と変換して1バイトで拾ってくれますが、バイナリモードだとそのまま2バイトで拾ってしまいます。 つまり、buffの中身は、 1回目:AAAAABBBBBCCCCCDDDD[CR]\0 2回目:[LF]\0 3回目:EEEEEFFFFFGGGGGHHHH[CR]\0 となり、まだ[LF]が残っているのでfeofは0を返します。 ファイルサイズを見るなどして、改行文字が2バイトになっていないか確認してみて下さい。

  • Haizy
  • ベストアンサー率40% (404/988)
回答No.3

ふたたび if(feof(fp)) あれあれ?? このままじゃ、上のif分って、0 = False じゃ無いですか???(^^; if(feof(fp)==0)   rtn_code[0] = '4'; else   rtn_code[0] = '8'; じゃないと、True返らないですねぇ~~!!   m( _ _;)m・・・老いたな<俺 でわ~~。

techtak
質問者

補足

え? それって逆ではないんですか? if(feof(fp)==0)   rtn_code[0] = '8'; /*ファイルの終わりではない(エラー)*/ else   rtn_code[0] = '4'; /*ファイルの終わり*/ 参考書には 「エンドオブファイル指示子がセットされている時、feof関数は非0を返し、 それ以外は0を返す。」 と、あります。 私は逆の理解をしてるんだろか・・・ (実は自信がないんです、コレに関しては・・・)(--;

回答No.2

fgets で NULL が帰ってきちゃってるから、 その if 文の中に入ってない。 だから、rtn_code[0] の中身が '8' のままってことなんじゃないですか?

  • Haizy
  • ベストアンサー率40% (404/988)
回答No.1

>feof は,指定したストリーム上の最後の入力操作で >ファイル終了標識が検出されると 0 以外の値を返し, >ファイル終了標識に達しなければ 0 を返します。 2行目に注目。終了の場合は、0以外です。 何が返ってくるかわからないんですね~。 この条件で、戻り値8を非EOFとしたいならば、 if(!feof(fp)) でなく、 if(feof(fp))   rtn_code[0] = '4'; else   rtn_code[0] = '8'; の方が良くないですか? NOT処理は、ない方が1サイクル分処理が早いですし、なによりバグになりかねません。(多用すると、バグの元です。) <<0/1 以外の戻り値の場合の動作を考えてみてください。(^^; でわ。

techtak
質問者

補足

Haizyさん、こんばんわ。 確かにNOT処理はよくなかったです。(^^; で、アドバイスの通りにしてみましたが、 やはり状況は変わりませんでした。 もう丸一日、参考書やWebで調べまくっていろいろやってみたのですが どうしても解決できないのです。 ここが最後の砦です! それから質問の補足ですが、ファイルは"rb"(バイナリモード)で 開いています。

関連するQ&A

  • 続・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] 「ここはこうしたらいいんじゃないかな?」的な事でかまいませんので、是非みなさんの意見を聞かせてください。

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

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

  • C++初心者です。ご指導よろしくお願いします。

    C++初心者です。ご指導よろしくお願いします。 C++で特定の行の値を読み込むプログラムを作っています。 a.txtとb.txtが入力ファイルで、c.txtが出力ファイルです。 a.txtには 237891 193203 1355876 ・ ・ ・ (以下1~5000000の数値がランダムに15000行分) b.txtには 0.333333 0.333333 0.397396 ・ ・ ・ (以下0.333333~0.822222までの数値がランダムに5000000行分) が書いてあって、 c.txtに a.txtの1行目の数値の行に対応するb.txtの値 a.txtの2~ a.txtの3~ ・ ・ ・ (以下15000行分) を出力するプログラムを作りたいと思っています。 以下のように、プログラムを書きましたが、a.txtが10行、b.txtが20行程度の時は問題なく動くのですが、行数が多くなると急に動かなくなります。 charのところを変えたり、offsetのところを変えたりしたのですが、最初の1行を読み込んだところで止まってしまいます。 (buffの値は=237891 no2の値は=237891まで) どのようにすれば動くようになるでしょうか? ご指導よろしくお願いします。 #include <stdio.h> #include <iostream> #include <fstream> #include <cstdlib> #include <cstring> using namespace std; int main(void) { FILE *fp,*fp2,*fp3; char buff[256],buff2[256]; long int offset[100],offset2[100]; long int max,max2; long int no=0; long int no2=0; for(no=1; no<=15000; no++){ fp = fopen("input/a.txt","r"); if(fp == NULL){ cout << "入力ファイルをオープンできません\n"; } for ( max = 0 ; !feof(fp) ; max++ ){ if ( max >= 100 ){ break; } offset[ max ] = ftell( fp ); fgets( buff, sizeof(buff), fp ); } fseek( fp, offset[no - 1], SEEK_SET ); fgets( buff, sizeof(buff), fp ); cout << "buffの値は=" << buff << "\n"; no2 = atoi(buff); cout << "no2の値は=" << no2 << "\n"; fp2 = fopen("input/b.txt","r"); if(fp2 == NULL){ cout << "入力ファイルをオープンできません\n"; } for ( max2 = 0 ; !feof(fp2) ; max2++ ){ if ( max2 >= 100 ){ break; } offset2[ max2 ] = ftell( fp2 ); fgets( buff2, sizeof(buff2), fp2 ); } fseek( fp2, offset2[no2 - 1], SEEK_SET ); fgets( buff2, sizeof(buff2), fp2 ); cout << "buff2の値は=" << buff2 << "\n"; fp3 = fopen("input/c.txt","a"); if(fp2 == NULL){ cout << "入力ファイルをオープンできません\n"; } fprintf(fp3, buff2); strcpy(buff,"0"); strcpy(buff2,"0"); no2=0; cout << "buff2は初期化されて=" << buff2 << "\n"; fclose(fp); fclose(fp2); fclose(fp3); } }

  • C言語、ファイル操作、fgets()について

    次のプログラムは入力された行を読み込み、コマンドラインで指定されたファイルに書き込みます。 空白行が入力されたら、入力の終了とみなしてファイルを閉じます。続いてファイルを入力用に開き、 fgets()を使ってファイルの内容を表示するものです。 (ソースコードが長くてすみません) #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { FILE *fp; char str[80]; /* コマンドライン引数を検査する */ if(argc!=2) { printf("ファイル名を指定してください\n"); exit(1); } /* 出力用にファイルを開く */ if((fp = fopen(argv[1], "w"))==NULL) { printf("ファイルを開くことができません\n"); exit(1); } printf("終了するには空白行を入力してください\n"); do { printf(": "); gets(str); strcat(str, "\n"); /* 改行を追加する */ if(*str != '\n') fputs(str, fp); } while(*str != '\n'); fclose(fp); /* 入力用にファイルを開く */ if((fp = fopen(argv[1], "r"))==NULL) { printf("ファイルを開くことができません\n"); exit(1); } /* ファイルを読み込み直す */ do { fgets(str, 79, fp); if(!feof(fp)) printf(str); } while(!feof(fp)); fclose(fp); return 0; } 【質問】fgets()内のint型の数値「79」がどうして79なのかが分かりません。     80でも良いような気がするのですが・・・

  • ファイルの出力

    コマンドラインで指定したファイルの内容を一行ずつ表示するプログラムです。一行表示するごとに次の行も表示するか尋ねます。 #include<stdio.h> #include<stdlib.h> #include<ctype.h> int main(int argc, char *argv[]) {  FILE *fp;  char str[80];  char ch;  if (argc != 2){   printf("コマンドライン引数が違います\n");   exit(1);  }  if ((fp = fopen(argv[1],"r")) == NULL){   printf("ファイルが開けません");   exit(1);  }  while(!feof(fp)){   fgets(str, 79, fp);   if (!feof(fp)) printf("%s",str);   printf("追加しますか?(y/n)");   gets(str);   if ( toupper(*str) == 'N') break;   printf("\n");  }     if (fclose(fp) == EOF){   printf("ファイルを閉じれません\n");   exit(1);  }  return 0; } while文の   gets(str);  if ( toupper(*str) == 'N') break; この部分を  ch = getchar();  if ( toupper(ch) == 'N') break; でやると上手く実行できないのですが、なぜでずか?

  • PHPでファイルポインタの移動

    現在。[EOF]になるまで1行読込んでは、ファイルポインタを移動させ すべての行を出力しています。 これをテキストの[EOF]よりも1行上のbbbbbbbbがある行(見た目上の最終行)のみを 出力したいのですがどうすればいですか? while(!feof($filepointer)){ $line = fgets($filepointer); print($line."<br />"); } ~log.txt~ aaaaaaaaaaaaa[改行コード] bbbbbbbbbbbbb[改行コード]←ココのみ取り出したい [EOF]

    • ベストアンサー
    • PHP
  • 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); } } 以上です。 このような場合どうしたらよいのでしょうか?また異なるやり方があればご教授お願いします。 よろしくお願いします。

  • fgets( ) の返り値は何?

    fgets( ) はファイル終端に行くと0を返すらしいけど それ以外の場合は何を返すんですか? if( fgets( buf, 10, fp ) == 0 ) break; のように、fgets( ) の返り値をそのまま使うことはできたけど 試しに、 char ret[255]; ret = fgets(buf, 10, fp); とするとコンパイルエラーでした。

  • 所有権root、600のファイルを読み書きしたいのですが…。

    所有権がrootでバーミッションが600のファイル (例えば、パスワードファイルなど) をPHPを使ってwebから読んだり書いたりしたいのですが、 どのようにしたら出来ますでしょうか? 例えば、次のようなコードです。 <?php $fp = fopen("/etc/shadow", "r"); while (!feof($fp)){ $line = fgets($fp, 4096); } fclose($fp); ?>

    • ベストアンサー
    • PHP
  • プログラムソースの誤りを教えてください

    CSVファイル(カンマでデータの要素が区切られている)の左から数えて15個目と16個目の間のデータを読みとるプログラムをつくりたいのですが、できません。どこがおかしいのか教えてください。 #include<stdio.h> int main(){ FILE *fp; char buff[562],yakusyoku[10]; int youso,n,konma; fp = fopen("jinji.csv","r"); if(fp == NULL) exit(1); fgets(buff,sizeof(buff),fp); n = 0,youso = 0,konma = 0; while (youso < sizeof(buff)){ if(buff[youso] == ','){ konma++; if (konma == 15){//カンマが15個になったら次の処理を行う while(buff[youso] != ','){//次のカンマ(16個目のカンマに会うまで次の処理を行う) yakusyoku[n] = buff[youso]; youso++,n++; break; } } } youso++; } fclose(fp); }