• ベストアンサー

ちょっとした疑問なんですが・・・(C言語)

何度も質問してごめんなさい! ちょっとした疑問なんですが、下記のプログラム中の、 while(!feof(in)) { ch = fgetc(in); if(!feof(in)) fputc(~ch, out); } のコードで、「while(!feof(in))」でストリーム「in」結び付けられているファイルの終わりに達していれば繰り返し処理を終えるのは分かるのですが、 なぜ、インクリメントも無くファイルの終わりまで文字を調べ進めることができるのでしょうか? 未熟者の私ですが教えて頂けないでしょうか? 【プログラム例】 #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { FILE *in, *out; unsigned char ch; if(argc!=3) { printf("使用法: <プログラム名> <入力ファイル名> " "<出力ファイル名>\n"); exit(1); } if((in = fopen(argv[1], "rb"))==NULL) { printf("入力ファイルを開くことができません\n"); exit(1); } if((out = fopen(argv[2], "wb"))==NULL) { printf("出力ファイルを開くことができません\n"); exit(1); } while(!feof(in)) { ch = fgetc(in); if(!feof(in)) fputc(~ch, out); } fclose(in); fclose(out); return 0; }

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

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

すみません。訂正。 戻り値がEOFを返すのはfgetcです。 #どこで勘違いしたんだか。 int ch; ... while ((ch = fgetc(in)) != EOF) { 書き込み のようにするということです。 まあCらしい書き方といえばそういえるし、わかりづらいといえばそうかもしれません。

Guchiken
質問者

お礼

回答ありがとうございます!!! 以後、参考にさせていただきます!! 回答本当にありがとうございました!

その他の回答 (4)

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

> 最後の1文字を読み込んだ直前にch=fgetc(in)がEOFを返すのではなく、 > さらに次の1文字読み込もうとしたときにEOFを返すから、 > それまでにすべての文字をfputc(~ch, out)で出力されているので > 問題は無いんじゃないでしょうか? この認識であってます。 master000さんが勘違いされています。 JIS規格の該当部分を引用しときます。 「そのストリームのファイル終了表示子がセットされている場合、又はストリームがファイルの終わりに 達している場合、そのストリームのファイル終了表示子をセットし、fgetc関数は EOFを返す」 7.19.7.1 最後のキャラクタを読み取ったときは最後のキャラクタを返し、EOFを返すわけではないですから、 上記のファイル終了表示子をセットするのは、最後に達してなおそこから 読み取ろうとしたときです。 ただまあ、ここの記述にあるとおり、fputc自体がファイル終了の情報を返すわけですから、 feofを使わないでも同じことはできます。 ただし、fputcの戻りを受けるのは unsigned char ch; だとまずいですけどね。

Guchiken
質問者

お礼

回答ありがとうございます!! 解釈があっているかちょっと不安だったので、 sakusaker7さんの回答で安心できました!ありがとうございます! >まずいですけどね。 私が勉強している本『独習C 第3版』には、 int fputc(int 文字 , FILE *ストリーム); という形式で、fputc関数が紹介されているのですが、 『「文字」はint型と定義されていますが、単にchar型を渡しても問題ありません。これは一般的によくとられる手法です』とあるんです。 別の本『新ANSI C言語辞典』で調べたところ、fputc()の戻り値は、書かれた「文字」を返すとあるんです。

  • master000
  • ベストアンサー率33% (16/48)
回答No.3

>ANo.2 最後をch = fgetc(in);で読み込むとEOF状態になり つぎのif(!feof(in)) は、feof(in)がtrueになり、!で結果falseになります。 よってfputc(~ch, out);は実行されません。 ということですね。

Guchiken
質問者

お礼

回答ありがとうございます!! 最後の1文字を ch = fgetc(in); でchに読み込んだ後、ファイル位置指示子を進めて、 さらに1文字読み込もうとした時、ch=fgetc(in); がEOFを返し、 その直後のfeof(in)が真になり、!で偽になる。 最後の1文字を読み込んだ直前にch=fgetc(in)がEOFを返すのではなく、 さらに次の1文字読み込もうとしたときにEOFを返すから、 それまでにすべての文字をfputc(~ch, out)で出力されているので 問題は無いんじゃないでしょうか? ちなみに実行しても問題はありませんでしたけど・・・・ どうなんでしょうか?私にはちょっと分かりません。

  • master000
  • ベストアンサー率33% (16/48)
回答No.2

あれ? while(!feof(in)) { ch = fgetc(in); if(!feof(in)) fputc(~ch, out); } 上のパターンだとファイル末尾の1バイトは出力されませんが いいのかな?

Guchiken
質問者

お礼

回答ありがとうございます!! >ファイル末尾の1バイトは出力されませんが どうしてファイル末尾の1バイトが表示されないんですか?? 教えて頂ければうれしいです。

noname#77845
noname#77845
回答No.1

fgetc()で一文字読み込んだ後、一文字分進めているからです。 他の関数も調べた方が勉強になると思いますよ。 fgetc() http://www9.plala.or.jp/sgwr-t/lib/fgetc.html 全般 http://www9.plala.or.jp/sgwr-t/

Guchiken
質問者

お礼

さっそくの回答ありがとうございます!! もうちょっと調べてから質問したほうが良かったみたいです…ごめんなさい! fgetc()が値を返すときに1文字分進めているんですね!わかりました!! 回答本当にありがとうございました!!

関連するQ&A

  • エラーがでてしまいます

    以下のプログラムなのですが、引数を与えると下のようなエラーになります。 #include<stdio.h> #include<stdlib.h> int main(int argc, char** argv) { FILE *in ,*out; unsigned char ch; if(argc != 3) { printf("入力エラーです。\n"); exit(1); } if((in = fopen(argv[1],"rb")) == NULL) { printf("入力ファイルが開けません。\n"); exit(1); } if((out = fopen(argv[2],"rb")) == NULL) { printf("出力ファイルが開けません。\n"); exit(1); } while(!feof(in)) { ch = fgetc(in); if(!feof(in)) fputc(~ch,out); } fclose(in); fclose(out); return 0 ; } tyobi@tyobi-laptop:~$ gcc test.c diary copy diary: file not recognized: File format not recognized collect2: ld はステータス 1 で終了しました どうしたらよいのでしょうか?

  • C言語の質問です

    下記のプログラムはコマンドラインからコピー元ファイルとコピー先ファイルを指定し、コピーするプログラムです。 (コピーの際にタブ文字を適切な数のスペースに置き換えます) /* ファイルをコピーしてタブを削除する */ #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { FILE *from, *to; char ch; int tab, count; /* コマンドライン引数の数が適切かどうか確認する */ if(argc!=3) { printf("使用法: <プログラム名> <コピー元> <コピー先>\n"); exit(1); } /* コピー元ファイルを開く */ if((from = fopen(argv[1], "r"))==NULL) { printf("コピー元ファイルを開くことができません\n"); exit(1); } /* コピー先ファイルを開く */ if((to = fopen(argv[2], "w"))==NULL) { printf("コピー先ファイルを開くことができません\n"); exit(1); } /* ファイルをコピーする */ count = 0; while(!feof(from)) { ch = fgetc(from); if(ch=='\t') { for(tab = count; tab<8; tab++) fputc(' ', to); count = 0; } else { if(!feof(from)) fputc(ch, to); count++; if(count==8 || ch=='\n') count = 0; } } fclose(from); fclose(to); return 0; } 【質問】 「ファイルをコピーする」部分のif文のelseブロック部分が何を行っているのか分かりません。 ひとつひとつの動作は分かるのですが、全体的に何をしようとしているのか分かりません! 教えていただけないでしょうか?

  • C言語の質問です

    下記のプログラムはテキストファイルを読み込み、AからZまでの文字(小文字、大文字は区別しない)がそれぞれ何回 現れたかを数えるプログラムです。 #include <stdio.h> #include <stdlib.h> #include <ctype.h> int count[26]; int main(int argc, char *argv[]) { FILE *fp; char ch; int i; /* ファイル名の指定を調べる */ if(argc!=2) { printf("ファイル名の指定がありません\n"); exit(1); } if((fp = fopen(argv[1], "r"))==NULL) { printf("ファイルを開くことができません\n"); exit(1); } while((ch=fgetc(fp))!=EOF) { ch = toupper(ch); if(ch>='A' && ch<='Z') count[ch-'A']++; } for(i=0; i<26; i++) printf("%c は %d 回出現\n", i+'A', count[i]); fclose(fp); return 0; } 1)int count[26]; で、なぜ26なのかが分かりません。 2)count[ch-'A']++; はどういう動作をするのか詳しく教えてほしいです。 3)よって、for文がどういう動作で表示しているのかが分かりません。 未熟者の私ですが、どなたか教えていただけないでしょうか?

  • 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; でやると上手く実行できないのですが、なぜでずか?

  • ファイル入出力について

    次のようなプログラムを作りました。 コマンドラインから二つのファイルの名前を読み取り、最初の引数のファイルを2番目の引数のファイルにコピーするプログラムです。 質問は下のプログラムのコメント /*この行が質問です*/ の所です。 //ファイルをコピーする の部分の始めに while(!feof(from)) という条件を書いているため、/*この行が質問です*/ の行は不要であると思いましたが、実際にこの一行をのぞいてコンパイルして実行したところ、日本語が文字化けしてコピーされてしまいました。その後、この行を追加してコンパイルして実行すると文字化けもなく実行できました。 なぜこの行が必要なのでしょうか。 よろしくお願いします。 //ファイルコピー #include<stdio.h> #include<stdlib.h> int main(int argc, char *argv[]) {   FILE *from, *to;   char ch;   //引数の数の確認   if (argc != 3) {     printf("引数の数が違います");     exit(1);   }   //コピー元ファイルを開く   if ((from = fopen(argv[1],"r")) == NULL ) {     printf("コピー元ファイルオープンエラー");     exit(1);   }   //コピー先ファイルを開く   if ((to = fopen(argv[2],"w") )== NULL ) {     printf("コピー先ファイルオープンエラー");     exit(1);   }   //ファイルをコピーする   while (!feof(from)) {     ch = fgetc(from);     if(ferror(from)) {       printf("コピー元ファイル読み込みエラー");       exit(1);     }     if (!feof(from))       /*この行が質問です*/       fputc(ch,to);     if (ferror(to)) {       printf("コピー先ファイル書き込みエラー");       exit(1);     }   }   if (fclose(from) == EOF) {     printf("コピー元ファイルクローズエラー");     exit(1);   }   if (fclose(to) == EOF) {     printf("コピー先ファイルクローズエラー");     exit(1);   }   return 0; }

  • 探索アルゴリズム

    テキストファイルを読み込んで、該当する文字列を含む行を表示するというプログラムを作りたいのです。ファイルを読み込むことはできるのですが、該当する文字列を含む行を表示するやり方がわかりません。どなたか助けてもらえないでしょうか? 一応私が作ってみたプログラムはこんな感じになったんですけど・・・ #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) {  FILE *fp;  char ch;  if( argc != 3)  {  printf(" 使用法 : <プログラム名> <ファイル名> <文字> \n");  return -1;  }  if((fp = fopen(argv[1],"r")) == NULL)  {  printf("ファイルを開くことができません\n");  return -1;  }  while(( ch = fgetc(fp)) != EOF)  if(ch == *argv[2])  {  printf("%cが見つかりました\n",ch);  break;  }  fclose(fp);  return 0; }

  • C言語の質問です

    #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { FILE *fpi, *fpo; unsigned char idat; /* 引数のチェック */ if (argc != 3) { fprintf(stderr, "Usage: %s [input] [output]\n", argv[0]); exit(1); } /* 入力画像のオープン */ if((fpi=fopen(argv[1], "rb")) == NULL){ fprintf(stderr, "input file open error\n"); exit(1); } /* 出力画像のオープン */ if((fpo=fopen(argv[2], "wb")) == NULL){ fprintf(stderr, "output file open error\n"); exit(1); } /* 入力画像の読込み */ while (fread(&idat, sizeof(unsigned char), 1, fpi) == 1){ /* 2倍の変換 */ if (idat * 2 > 255) { idat = 255; } else { idat = idat * 2; } /* 変換データの書出し */ if(fwrite(&idat, sizeof(unsigned char), 1, fpo) != 1){ fprintf(stderr, "data write error\n"); exit(1); } } fclose(fpi); fclose(fpo); return (0); } このプログラムをグレースケール化のプログラムに修正してください お願いします

  • ファイル

    AからZまでの文字が何回出力されるか数えるプログラムなのですが、うまく出力されません。 どこを変えればよろしいでしょうか。 #include<stdio.h> #include<stdlib.h> #include<ctype.h> int count[26]; int main(void) { char str[100] = "xyzYZZ\n"; FILE *fp; char *p; int i; char ch; if((fp = fopen("myfile","w")) == NULL){ printf("ファイルを開くことが出来ません"); exit(1); } p = str; while(*p){ if(fputc (*p,fp) == EOF){ printf("ファイル書き込みエラー"); exit(1); } p++; } fclose(fp); if((fp = fopen ("myfile","r")) == NULL){ printf("ファイルを開くことが出来ません"); exit(1); } while((ch == fgetc(fp)) != EOF){ ch = toupper(ch); if( ch >= 'A' && ch <='Z' ) count[ch - 'A']++ ; } for( i=0 ; i<26 ; i++) printf("%c は %d 回出現\n",i + 'A', count[i]); fclose(fp); return 0; }

  • ファイル操作のプログラム

    アルファベットの小文字を大文字に変換しながらファイルをコピーするプログラムですが形として書いてみたのですが・・・小→大に変換する場所、コマンドライン引数、細かい間違い等教えてくださればと思います。プログラムの条件として ・コマンドラインには,「実行プログラム名」「コピー元ファイル名」「コピー先ファイル名」を入力してプログラムを実行し,これらを引数としてコピーを行う. ・ コマンドラインへの入力が正しく行われているか(コピー元ファイルやコピー先ファイルも入力されているか)確認を行う. ・ファイルから読み取った文字が,小文字であるかを判断する必要があるので,ファイルから文字を「1文字ずつ」読み取って, 小文字であれば変換してコピー先に出力, その他の場合はそのままコピー先に 見にくいものではありますがよろしくお願いします。 #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[])) { FILE *infp, *outfp; int ch; if ( argc != 3 ){ /* コマンドラインからの入力が正しいか */ printf("There is no FILE NAME. \n"); exit(1); } if ( infp != argv[1] ) { printf("INPUT FILE OPEN error. \n"); } else { if ( outfp != [2] ) { printf("OUTPUT FILE OPEN error. \n"); } else { /* 入力・出力ファイルの条件が整ったので,コピー作業を行う */ if ((infp = fopen(argv[1], "r")) == NULL) { /* コピー元ファイルのオープン */ printf("can't open %s\n", argv[1]); return 1; } if ((outfp = fopen(argv[2], "w")) == NULL) { /* コピー先ファイルのオープン */ printf("can't open %s\n", argv[2]); fclose(infp); /* コピー元ファイルのクローズ*/ return 1; } while ((ch = fgetc(infp)) != EOF) { fputc(ch, outfp); /* コピー先ファイルにコピー元ファイルの内容を書き込む*/ } fclose(infp); } fclose(outfp); } return 0; }