• 締切済み

ファイル内の特定の文字列だけを書き出す

中身が a a a b b b a … と書かれたファイルがあります。 このファイルの中の文字のうち、aのみを書き出したく、以下のプログラムを作成したのですが、上手く動きません。 何がおかしいか教えていただけないでしょうか。 ちなみにエラーは、 Segmentation fault (core dumped) と出ます。 #include <stdio.h> void main() { int x; float c[2160]; FILE *fp; fp = fopen("test.txt", "r"); if(fp == NULL) { printf("ファイルを開くことが出来ませんでした.¥n"); return; } x = 0; while (feof(fp)==0){ c[x] = getc(fr); if(strcmp(c[x], "a")==0) putchar(c[x]); x++; } fclose(fp); }

みんなの回答

回答No.5

たくさんの方が回答されていますが、私も丁寧に解説したいと思います。  まず、文字列は文字の配列です。また、文字はchar型ですから、浮動小数点単精度実数型のfloatに代入すると、文字ではなくて数値としてfloatに代入されてしまいます。(これを暗黙の型変換といいます。)  最初に考えなければいけないのは、どのようなアルゴリズムを組めば動くかです。型や関数を考えるのは二の次です。今回の場合は次のようになります。 1. ファイル終端(eof)かどうか確認する。 2. 1文字ファイルから取ってくる。 3. その文字が'a'ならば出力に書き出す。 4. 1へ戻る  そして、これを少しプログラミング言語っぽい言語へ頭のなかで置き換えましょう。 ----- while(ファイル終端じゃない){ c = 1文字取得 if(cは'a'であるか) cを出力 } -----  最後に、それに対応するC言語を書きます。 ---- #include <stdio.h> int main(void) { char c; FILE *fp = fopen("test.txt", "r"); if(fp == NULL) { printf("ファイルを開くことが出来ませんでした.\n"); return -1; } while((c = getc(fp)) != EOF){ if(c == 'a') putchar(c); } fclose(fp); return 0; } ---- 0. main関数はこのように書くのがいいみたいですが、そこら辺はコンパイラがよろしくやってくれるはずなので気にしなくていいかもしれませんが一応。 1. 1文字だけ記憶しなければいけないので、`char c;`とします。 2. `int x;`は、配列を使用しないので必要ありません。使用する場合も、配列のインデックスを表す文字は`i`や`idx`等使用すると、他人が見てもわかりやすいソースコードとなります。 3. getcの仕様を見ると、ファイル終端までたどり着くと返り値がEOFになるので、(c = getc(fp)) != EOFはそれを利用しています。 4. 文字リテラルは'a'です。

回答No.4

まず、配列 cが 2160の固定長ですから、x=2160になった段階で、メモリを壊して います。 このプログラムのままだと、x=2160になっ時に、処理規模オーバーとして、 エラーとして、プログラムを終了させるべきです。 次に、int getc(FILE *stream) なのに、なぜcをfloat型に宣言したのでしょう。 cはint型で宣言し直すべきです。flatは単精度浮動小数点(実数)なので、 文字、文字列操作の処理にとっては不適切です。 文字の比較の仕方 なぜ、c[x] == 'a' ではなく、strcmpを使ったのでしょう。 strcmpは、文字列の配列同士を、0が出現するまで比較し続けます。 この場合、float型で一文字を受け取り、文字列の比較をしているので、'a'の後に 何があるか分かりません。 cの宣言をint に下上で、=='a' と書き改めるべきでしょう。 また、このプログラムは、単に一文字ずつ読み込んで、比較するでなので、 配列にため込む必要はありません。xという変数も必要ないし、cを配列として宣言 する必要もありません。 なお、getcはreturn値 EOFで、ファイルの終わりが検出されます。 feofを使う必要は無いでしょう。 feof以外の点をまとめると、以下の様に修正することになります。 #include <stdio.h> void main() { /* int x; */ /* float c[2160]; */ int c; FILE *fp; fp = fopen("test.txt", "r"); if(fp == NULL) { printf("ファイルを開くことが出来ませんでした.¥n"); return; } x = 0; while (feof(fp)==0){ /* c[x] = getc(fr); */ c = getc(fr); /* if(strcmp(c[x], "a")==0) */ if(c == 'a') /* putchar(c[x]) */ putchar(c); /* x++; */ } fclose(fp); }

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

strcmp については, プロトタイプが存在しないので勝手に「よきにはからった」可能性がありますね>#2. あと, feof や getc の仕様のせいで, #1 もぎりぎりの状況のときにおかしな挙動をすることが想定できる.

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.2

え?これってコンパイルできるんですか? いろいろ間違いがあってコンパイルすらできないはずなんですが。 Segmentation fault (core dumped) これは、不正なメモリアクセスがあった場合に発生するエラーです。 よくあるのが、「配列の添字を間違えて、領域外にアクセスしてしまった」というものです。 その視点で見ると、一番疑わしいのは、c[x]でxが配列の範囲外(c[2160]と宣言しているので、-1以下か2160以上)になっていないか、というものです。 ただ、範囲外になったからと言って必ず発生するとは限らないのがCの面倒なところです。 float c[2160]; なぜfloatなんですか? ↓のように使ってますが、getcの戻り値と型が一致しません。 c[x] = getc(fr); frは定義されていません。fpの間違いでしょう。 strcmp(c[x], "a") strcmpのマニュアルを見てください。 第1引数に float型を指定することはできません そうでなくても、 getcで読み込んだ「1文字を表す数値」と「文字列」を比較することはできません。 getcで読み込んだ1文字との比較だったら、シングルクオートを使って c[x] == 'a' ですし、 aというのが複数の文字から成る文字列だったら、getcで読み込んだ1文字ではなく、文字列として読み込む必要があります。 変数x ファイルの内容を全て保存するなら、このプログラムのように配列に保存することになります。 しかし、このプログラムでは、後から参照することはありません。 それなら、c[x]などという配列を使う必要は無いはずです。

  • maiko0318
  • ベストアンサー率21% (1483/6969)
回答No.1

#include <stdio.h> void main() { int x; char c; FILE *fp; fp = fopen("test.txt", "r"); if(fp == NULL) { printf("ファイルを開くことが出来ませんでした¥n"); return; } while (feof(fp)==0){ c = getc(fp); if(c == 'a') putchar(c); } fclose(fp); } これで十分

関連するQ&A