情報処理4レポート課題(3)の解答例

更新:2008年10月7日


  1. file5.cを改訂し,次の3つのファイルそれぞれに対して,ファイル内の文字'a'の個数を画面表示するようにして下さい。

  2. fgetc_count_a.c
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void){
    	FILE *fp;
    	const char *filename1="/usr/share/dict/words";
    	const char *filename2="freqword-linux.txt";
    	const char *filename3="TomSawer1.txt";
    	int ch;
    	int count;
    
    	fp=fopen(filename1, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename1);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch =='a'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename1, count);
    	fclose(fp);
    
    	fp=fopen(filename2, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename2);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch =='a'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename2, count);
    	fclose(fp);
    
    	fp=fopen(filename3, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename3);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch =='a'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename3, count);
    	fclose(fp);
    	return 0;
    }
    
    file5.cを改訂し,次の3つのファイルそれぞれに対して,ファイル内の数字の個数を画面表示するようにして下さい。 ただし、以下のできるだけ番号の大きい方法を採用して下さい。
    1. 第一ステップとしては一つ一つ判定するような
      if(ch=='0' || ch=='1' ||...)
      
    2. ASCIIで数字は連番であることを利用して不等号を用いましょう。
      if(ch>='0' && ...)
      
    3. 適切な文字操作関数を用いましょう。

    fgetc_count_digit0.c
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void){
    	FILE *fp;
    	const char *filename1="/usr/share/dict/words";
    	const char *filename2="freqword-linux.txt";
    	const char *filename3="TomSawer1.txt";
    	int ch;
    	int count;
    
    	fp=fopen(filename1, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename1);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch =='0' ||
    			ch=='1' ||
    			ch=='2' ||
    			ch=='3' ||
    			ch=='4' ||
    			ch=='5' ||
    			ch=='6' ||
    			ch=='7' ||
    			ch=='8' ||
    			ch=='9'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename1, count);
    	fclose(fp);
    
    	fp=fopen(filename2, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename2);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch =='0' ||
    			ch=='1' ||
    			ch=='2' ||
    			ch=='3' ||
    			ch=='4' ||
    			ch=='5' ||
    			ch=='6' ||
    			ch=='7' ||
    			ch=='8' ||
    			ch=='9'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename2, count);
    	fclose(fp);
    
    	fp=fopen(filename3, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename3);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch =='0' ||
    			ch=='1' ||
    			ch=='2' ||
    			ch=='3' ||
    			ch=='4' ||
    			ch=='5' ||
    			ch=='6' ||
    			ch=='7' ||
    			ch=='8' ||
    			ch=='9'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename3, count);
    	fclose(fp);
    	return 0;
    }
    
    fgetc_count_digit1.c
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void){
    	FILE *fp;
    	const char *filename1="/usr/share/dict/words";
    	const char *filename2="freqword-linux.txt";
    	const char *filename3="TomSawer1.txt";
    	int ch;
    	int count;
    
    	fp=fopen(filename1, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename1);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch >='0' && ch <= '9'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename1, count);
    	fclose(fp);
    
    	fp=fopen(filename2, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename2);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch >='0' && ch <= '9'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename2, count);
    	fclose(fp);
    
    	fp=fopen(filename3, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename3);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if( ch >='0' && ch <= '9'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename3, count);
    	fclose(fp);
    	return 0;
    }
    
    fgetc_count_digit2.c
    #include<stdio.h>
    #include<stdlib.h>
    #include<ctype.h>
    
    int main(void){
    	FILE *fp;
    	const char *filename1="/usr/share/dict/words";
    	const char *filename2="freqword-linux.txt";
    	const char *filename3="TomSawer1.txt";
    	int ch;
    	int count;
    
    	fp=fopen(filename1, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename1);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if(isdigit(ch)){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename1, count);
    	fclose(fp);
    
    	fp=fopen(filename2, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename2);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if(isdigit(ch)){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename2, count);
    	fclose(fp);
    
    	fp=fopen(filename3, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename3);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if(isdigit(ch)){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename3, count);
    	fclose(fp);
    	return 0;
    }
    
  3. file5.cを改訂し,次の3つのファイルそれぞれに対して,ファイルの行数を画面表示するようにして下さい。
    fgetc_count_line.c
    #include<stdio.h>
    #include<stdlib.h>
    #include<ctype.h>
    
    int main(void){
    	FILE *fp;
    	const char *filename1="/usr/share/dict/words";
    	const char *filename2="freqword-linux.txt";
    	const char *filename3="TomSawer1.txt";
    	int ch;
    	int count;
    
    	fp=fopen(filename1, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename1);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if(ch=='\n'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename1, count);
    	fclose(fp);
    
    	fp=fopen(filename2, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename2);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if(ch=='\n'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename2, count);
    	fclose(fp);
    
    	fp=fopen(filename3, "r");
    	if(fp==NULL){
    		printf("Can't Open File %s\n", filename3);
    		exit(1);
    	}
    	count=0;
    	while(1){
    		ch=fgetc(fp);
    		if(ch==EOF){
    			break;
    		}
    		if(ch=='\n'){
    			count++;
    		}
    	}
    	printf("%s:%d\n", filename3, count);
    	fclose(fp);
    	return 0;
    }
    
  4. file5.cを改訂し,2つの入力ファイルが同じ内容か否か、異なる内容ならば何文字(バイト)目から異なるかを画面表示するようにして下さい。 例えば、 C.txtC2.txt について適用して下さい。また、良い例題を示して下さい。
    fgetc_diff.c
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(void){
    	FILE *fp1, *fp2;
    	const char *filename1="C.txt";
    	const char *filename2="C2.txt";
    	int ch1, ch2;
    	int count=1;
    
    	fp1=fopen(filename1, "r");
    	if(fp1==NULL){
    		printf("Can't Open File %s\n", filename1);
    		exit(1);
    	}
    	fp2=fopen(filename2, "r");
    	if(fp2==NULL){
    		printf("Can't Open File %s\n", filename2);
    		exit(1);
    	}
    
    	while(1){
    		ch1=fgetc(fp1);
    		ch2=fgetc(fp2);
    		if(ch1==EOF && ch2==EOF){
    		  printf("Exactly Same\n");
    			break;
    		}
    		else if(ch1!=ch2){
    		  printf("%d-th Characters (%c and %c) are different.\n", count, ch1, ch2);
    			break;
    		}
    		count++;
    	}
    	fclose(fp1);
    	fclose(fp2);
    	return 0;
    }
    

以下は、皆さんの幾つかの考察・感想に対するコメントです。
作業ディレクトリ以外にあるファイルを読み込む事は可能ですか?
可能です。実際、皆さんは作業ディレクトリ以外にある/usr/share/dict/wordを読み込んでいます。詳しくは「絶対パス」について調べて下さい。
aの個数があまりにも多すぎたので一旦、自分で作ったテキストファイルでプログラムを 実行させた。
これ大事です。
"a"と'a'の違いが分からなかった。はじめト ライした時に"a"でやってみたがエラーが出てしまったので、'a'でやってみたらエラーが 出なかったので解決したが何が違うか分からなかった。
"a"は文字列で、プログラム中では先頭文字'a'のアドレスを表します。 'a'は文字です。
なぜchがintなのか非常に疑問
EOFは計算機内部では-1で表されています。 一方で文字型の範囲(0〜255)では負を表すことができません。 そこで、chをint型にして文字もEOFも表すことができるようにしています。
カウント用の変数もなしに次の文字へ移っていくのが不思議だった。 fgetcの機能なのかもしれないので、調べてみようと思った。
良いところに気がつきましたね。 簡単に云えばfgetcの仕様ですが、是非、調べてみて下さい。
if(ch=='0' && ch=='1' &&...)
の部分は
if(ch=='0' || ch=='1' ||...)
なのではないでしょうか?試しに両方でやってみた所前者ではうまく行きませんでしたが 後者ならうまく行きました。
すみません。誤りでした。 御指摘の通りです。
このように複数ファイルがある場合、scanfからファイル名を打ち込んでそれを出力させ ることが出来れば、その都度プログラムを書き換えることもなくて済むので便利だろうな と感じました。
良いところに気がつきましたね。 是非、挑戦してみて下さい。
数値計算系プログラムは正解しているのかわからないので、 正解の実行結果の数値だけでも示して欲しいです。
気持ちは分かりますが、そこは自分で、 検算用に正解が分かるファイルを作成してテストして下さい。
        FILE *fp1,*fp2;
        const char *filename1="C.txt";
        const char *filename2="C2.txt";
        int ch1,ch2;
        int uh;
        uh=0;
        FILE *fp1,*fp2;
        int ch1,ch2;
        int uh;
        uh=0;
        const char *filename1="C.txt";
        const char *filename2="C2.txt";
ではエラーが出た。(何番目かインクリメントしておく変数)uhの宣言の順番が関係して いるのかと思ったが違うようだ。なぜ上が実行できて下が実行できないのかわからない。
変数の宣言を全て終えてから(上で云うfilename1とfilename2の宣言) プログラム文(上で云うuh=0)を書いて下さい。
4番で、=!にすると数が出るが、!=にすると0になった。 なぜだろうか。
「=!」と「!=」では意味が異なるからです。 前者は「右辺をビット反転して左辺に代入する」ことを表し、 後者は「左辺と右辺が同じか否かを比較する」ことを表します。
今回の問題において「何か良い例題を示してください」とありましたが、「C.txtとC2.tx tで違う文字があった場合、何行目の何文字目に入っているか」のような事ではなくて 自分でなにか適当な文章を改編して、それの間違いの文字数を表示させる、というような 出題意図だったのでしょうか。
そうです。
while文の中でelseの使い方が分からなくなりました…。if…そうじゃなかった場合さ らにif…としたいときはまたelseをつけるべきなのでしょうか?
つけるべきです。
「ファイルをオープンできないとき」について、もう一度読み直してみました。前回でもやっている事は分かったのですが、「ディレクトリを移動した」というのが私の端末の表示(bash-2.05b)となっているとわからないので、先生の端末みたいに[〜〜 \ ]みたいな表示にしたかったんです。AMI(でしたっけ?)とかで設定を変更したりすればいいのでしょうか?
GNOME端末上で、
PS1="[\w] "
とタイプすると、 それ以降の表示が変わります。 ただし、別のGNOME端末には反映されません。 永続的に設定したい場合には、ホームディレクトリに .bashrcをemacsで新規作成して、
PS1="[\w] "
と記述した後に、GNOME端末上で、
source .bashrc
とタイプします。 何か不具合が起きて変更を戻したければ、 ファイル.bashrcを削除するか名前変更して再ログインします。

何かありましたら、 まで。