- ベストアンサー
ファイルの読み書きと行移動について
ファイルaとファイルbから1行ずつ順にデータを読み込んでその行の大小関係を比較して、小さい方の行(同じ大きさなら両方)をファイルcに書き込むプログラムを作成したいと考えています。 そこで、以下のようなソースコード(途中まで)を書いてみました。 #include <stdio.h> main() { FILE *fpa,*fpb,*fpc; char fpa_data[200],fpb_data[200]; fpa=fopen("filea.txt","r"); fpb=fopen("fileb.txt","r"); fpc=fopen("filec.txt","a"); fscanf(fpa,"%s\n",fpa_data); fscanf(fpb,"%s\n",fpb_data); x = strcmp( fpa_data,fpb_data); if(x<0) fprintf(fpc,"%s\n",fpa_data); else if(x=0) fprintf(fpc,"%s\n%s\n",fpa_data,fpb_data); else fprintf(fpc,"%s\n",fpb_data); } このソースコードですと、最初の1行目のみが正しく実行されると思いますが、これを2行目以降の行に対しても行うようにするには、どのようにすればよいでしょうか? ご回答宜しくお願いします。
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
>if (fgets(buff_a, BUFFSIZE, fp_a) == NULL) break; >ですと、行の終わりでwhileループから抜け出してしまい、 >1行目しかファイルcに書き込まれないような気がします。 いえいえ。 fgetsはファイルから1行読み込んで、その文字列を返します。 もしファイルの終端までいったら、NULLを返します。 >あと、ファイルの一方が先に終端までいった際には、もう一方の >ファイルの残りの行全てをファイルcに書き出したいのですが、 >どのようにすればいいでしょうか? 各ファイルが終端にいったかどうかをあらわすフラグを 用意すればいいでしょう。 たとえばこのように(a_is_endとb_is_end)。 #include <stdio.h> #include <string.h> int main(void) { #define BUFFSIZE 256 char buff_a[BUFFSIZE]; char buff_b[BUFFSIZE]; FILE *fp_a = fopen("a", "r"); FILE *fp_b = fopen("b", "r"); FILE *fp_c = fopen("c", "w"); int a_is_end = 0; int b_is_end = 0; while (1) { if (!a_is_end && fgets(buff_a, BUFFSIZE, fp_a) == NULL) a_is_end = 1; if (!b_is_end && fgets(buff_b, BUFFSIZE, fp_b) == NULL) b_is_end = 1; if (a_is_end && b_is_end) break; if (!a_is_end && !b_is_end) { switch (strcmp(buff_a, buff_b)) { case -1: fprintf(fp_c, "%s", buff_a); break; case 0: fprintf(fp_c, "%s%s", buff_a, buff_b); break; case 1: fprintf(fp_c, "%s", buff_b); break; } } if (b_is_end) fprintf(fp_c, "%s", buff_a); if (a_is_end) fprintf(fp_c, "%s", buff_b); } fclose(fp_a); fclose(fp_b); fclose(fp_c); return 0; }
その他の回答 (7)
- HOGERA3
- ベストアンサー率35% (50/139)
> case文中で不等号を含む条件分岐は書けるのでしょうか?(多分無理だと思いますが・・・) おっしゃるとおり、無理です。 if文を使うのが普通の方法でしょう。
お礼
何度もありがとうございました。
- yatokesa
- ベストアンサー率40% (201/496)
> >> result = stata ? 1 : -1; >の文はどういったことをしているのでしょうか? まず、この if文(else)に入る条件は ファイルAまたは ファイルBのいずれかが既にファイルの終端まで達している場合です。 stata 及び statbは fgetsの戻り値を格納する変数で、ファイルが終端に達していれば NULLが入ってますよね。 result = stata ? 1 : -1 はご存じかもしれませんが、三項演算子で、stataが 0(NULL)ではないとき、resultに 1を格納、0以外の時は -1を格納します。つまり、stata (ファイルA)にデータが残っている場合は 1を入れ、stataが空の時(ファイルBにデータが残っているとき)は -1を入れます。 ...とここまで書いて、バグに気が付きました^^;)。 --- int stata = 1, statb = 1; while (1) { if (stata) stata = fgets (fpa_data, 200, fpa); if (statb) statb = fgets (fpb_data, 200, fpb); if (stata && statb) { result = strcmp (fpa_data, fpb_data); } else if (stata || statb) { result = stata ? 1 : -1; } else { break; } if (result <= 0) fprint (fpc, "%s\n", fpa_data); if (result >= 0) fprint (fpc, "%s\n", fpb_data); } --- #はづかしい...
お礼
なるほど、そういうことだったんですね。 何度もありがとうございました。
- HOGERA3
- ベストアンサー率35% (50/139)
ちょっと注意。 strcmp(a, b)の戻り値は、 ・a < b のとき ゼロより小さいint (-1とは限らない) ・a > b のとき ゼロより大きいint(1とは限らない) ・a == b のとき 0 ですので、No.4のように-1、1と比較するのは よくないでしょう。 (自分で書いといてなんなんですが)
補足
度々ありがとうございます。 私の処理系では-1,0,1でも問題ありませんでしたが、念のために変えといた方がいいですね。 if文を使ってなら、 int x; x=strcmp(buff_a,buff_b); if(x<0); ・・・ と書けますが、 case文中で不等号を含む条件分岐は書けるのでしょうか?(多分無理だと思いますが・・・)
- yatokesa
- ベストアンサー率40% (201/496)
締め切られていないようなので、参考までに自分のソースを改造して要求仕様に合わせてみました。 --- int stata = 1, statb = 1; while (stata || statb) { if (stata) stata = fgets (fpa_data, 200, fpa); if (statb) statb = fgets (fpb_data, 200, fpb); if (stata && statb) { result = strcmp (fpa_data, fpb_data); } else { result = stata ? 1 : -1; } if (result <= 0) fprint (fpc, "%s\n", fpa_data); if (result >= 0) fprint (fpc, "%s\n", fpb_data); } ---
補足
度々ありがとうございます。 早速、質問させていただきたいのですが、 stataは普通の変数と考えれば宜しいのでしょうか? それとも、何か特別な意味があるのでしょうか? また、 >> result = stata ? 1 : -1; の文はどういったことをしているのでしょうか? いままで、こういった文を見たことがないもので・・ 低レベルな質問と思いますが、宜しければご回答をお願いします。
- yatokesa
- ベストアンサー率40% (201/496)
あ、いきなり間違いに気が付きました^^;)。 while (stata && statb) { -> while (stata || statb) { でした。
- yatokesa
- ベストアンサー率40% (201/496)
若干条件があいまいなので、いくつか仮定して書いてみました。 ファイルA, ファイルBは昇順にソート済である。 同じ行同士を比較するのではなく、AとBのファイルをマージしながら昇順に書き込む。 fopen以降の例 --- stata = fgets (fpa_data, 200, fpa); statb = fgets (fpb_data, 200, fpb); while (stata && statb) { if (stata && statb) { result = strcmp (fpa_data, fpb_data); } else { result = stata ? 1 : -1; } if (result <= 0) { fprint (fpc, "%s\n", fpa_data); stata = fgets (fpa_data, 200, fpa); } else { fprint (fpc, "%s\n", fpb_data); statb = fgets (fpb_data, 200, fpb); } } --- #未検証です。
お礼
ご回答ありがとうございます。 >ファイルA, ファイルBは昇順にソート済である。 >同じ行同士を比較するのではなく、AとBのファイルをマー>ジしながら昇順に書き込む。 せっかく回答して頂いて申し訳ないのですが、ファイルA とファイルBは昇順にソート済みではないのです。私としましては、1行1行の大きさを調べながらファイルに書き込んでいくといったプログラムを作成したいと考えておりました。 誤解を与える表現で申し訳ございませんでした。
- HOGERA3
- ベストアンサー率35% (50/139)
とりあえずどっちかのファイルの終端までいったら そこでおしまいってことにするとこんな感じでしょうか。 #include <stdio.h> #include <string.h> int main(void) { #define BUFFSIZE 256 char buff_a[BUFFSIZE]; char buff_b[BUFFSIZE]; FILE *fp_a = fopen("a", "r"); FILE *fp_b = fopen("b", "r"); FILE *fp_c = fopen("c", "w"); while (1) { if (fgets(buff_a, BUFFSIZE, fp_a) == NULL) break; if (fgets(buff_b, BUFFSIZE, fp_b) == NULL) break; switch (strcmp(buff_a, buff_b)) { case -1: fprintf(fp_c, "%s", buff_a); break; case 0: fprintf(fp_c, "%s%s", buff_a, buff_b); break; case 1: fprintf(fp_c, "%s", buff_b); break; } } fclose(fp_a); fclose(fp_b); fclose(fp_c); return 0; }
補足
レスありがとうございます。 少し、分からないことがありますので、質問させていただきたいのですが、 if (fgets(buff_a, BUFFSIZE, fp_a) == NULL) break; ですと、行の終わりでwhileループから抜け出してしまい、 1行目しかファイルcに書き込まれないような気がします。 あと、ファイルの一方が先に終端までいった際には、もう一方のファイルの残りの行全てをファイルcに書き出したいのですが、どのようにすればいいでしょうか? ご回答宜しくお願い致します。
お礼
お礼の内容を回答に対する補足のところに書いてしまいました。申し訳ございませんでした。
補足
ご回答ありがとうございます。 >いえいえ。 fgetsはファイルから1行読み込んで、その文>字列を返します。 もしファイルの終端までいったら、N >ULLを返します。 なるほど、fgetsは文末まで順に読み込んでくれるのですね。fscanfは1行読み込んだら終わってしまいますので、私が最初に考えたプログラムではどうすることもできませんね。(笑) >各ファイルが終端にいったかどうかをあらわすフラグを >用意すればいいでしょう。 >たとえばこのように(a_is_endとb_is_end)。 そう考えたらよかったんですね。恐らく自分ひとりで考えていたら、そういう発想はできなかったと思います。 プログラムの方も先ほど実行したところ、きちんと動作しました。どうもありがとうございました。 Cをはじめて1ヶ月の初心者ですので、これからもお世話になることがあるかもしれませんが、その時には、宜しくお願い致します。(m_m)