• ベストアンサー

ファイルの読み書きと行移動について

 ファイル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行目以降の行に対しても行うようにするには、どのようにすればよいでしょうか?  ご回答宜しくお願いします。

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

  • ベストアンサー
  • HOGERA3
  • ベストアンサー率35% (50/139)
回答No.4

>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; }

linuxbeginner
質問者

お礼

お礼の内容を回答に対する補足のところに書いてしまいました。申し訳ございませんでした。

linuxbeginner
質問者

補足

ご回答ありがとうございます。 >いえいえ。 fgetsはファイルから1行読み込んで、その文>字列を返します。 もしファイルの終端までいったら、N >ULLを返します。 なるほど、fgetsは文末まで順に読み込んでくれるのですね。fscanfは1行読み込んだら終わってしまいますので、私が最初に考えたプログラムではどうすることもできませんね。(笑) >各ファイルが終端にいったかどうかをあらわすフラグを >用意すればいいでしょう。 >たとえばこのように(a_is_endとb_is_end)。 そう考えたらよかったんですね。恐らく自分ひとりで考えていたら、そういう発想はできなかったと思います。  プログラムの方も先ほど実行したところ、きちんと動作しました。どうもありがとうございました。    Cをはじめて1ヶ月の初心者ですので、これからもお世話になることがあるかもしれませんが、その時には、宜しくお願い致します。(m_m)

その他の回答 (7)

  • HOGERA3
  • ベストアンサー率35% (50/139)
回答No.8

> case文中で不等号を含む条件分岐は書けるのでしょうか?(多分無理だと思いますが・・・) おっしゃるとおり、無理です。 if文を使うのが普通の方法でしょう。

linuxbeginner
質問者

お礼

何度もありがとうございました。

  • yatokesa
  • ベストアンサー率40% (201/496)
回答No.7

> >> 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);  } --- #はづかしい...

linuxbeginner
質問者

お礼

 なるほど、そういうことだったんですね。  何度もありがとうございました。

  • HOGERA3
  • ベストアンサー率35% (50/139)
回答No.6

ちょっと注意。 strcmp(a, b)の戻り値は、 ・a < b のとき ゼロより小さいint (-1とは限らない) ・a > b のとき ゼロより大きいint(1とは限らない) ・a == b のとき 0 ですので、No.4のように-1、1と比較するのは よくないでしょう。 (自分で書いといてなんなんですが)

linuxbeginner
質問者

補足

度々ありがとうございます。 私の処理系では-1,0,1でも問題ありませんでしたが、念のために変えといた方がいいですね。 if文を使ってなら、 int x; x=strcmp(buff_a,buff_b); if(x<0); ・・・  と書けますが、  case文中で不等号を含む条件分岐は書けるのでしょうか?(多分無理だと思いますが・・・)

  • yatokesa
  • ベストアンサー率40% (201/496)
回答No.5

締め切られていないようなので、参考までに自分のソースを改造して要求仕様に合わせてみました。 ---  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);  } ---

linuxbeginner
質問者

補足

 度々ありがとうございます。  早速、質問させていただきたいのですが、  stataは普通の変数と考えれば宜しいのでしょうか?  それとも、何か特別な意味があるのでしょうか?  また、  >> result = stata ? 1 : -1; の文はどういったことをしているのでしょうか?  いままで、こういった文を見たことがないもので・・  低レベルな質問と思いますが、宜しければご回答をお願いします。

  • yatokesa
  • ベストアンサー率40% (201/496)
回答No.3

あ、いきなり間違いに気が付きました^^;)。  while (stata && statb) { ->  while (stata || statb) { でした。

  • yatokesa
  • ベストアンサー率40% (201/496)
回答No.2

若干条件があいまいなので、いくつか仮定して書いてみました。 ファイル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);   }  } --- #未検証です。

linuxbeginner
質問者

お礼

ご回答ありがとうございます。 >ファイルA, ファイルBは昇順にソート済である。 >同じ行同士を比較するのではなく、AとBのファイルをマー>ジしながら昇順に書き込む。  せっかく回答して頂いて申し訳ないのですが、ファイルA とファイルBは昇順にソート済みではないのです。私としましては、1行1行の大きさを調べながらファイルに書き込んでいくといったプログラムを作成したいと考えておりました。  誤解を与える表現で申し訳ございませんでした。

  • HOGERA3
  • ベストアンサー率35% (50/139)
回答No.1

とりあえずどっちかのファイルの終端までいったら そこでおしまいってことにするとこんな感じでしょうか。 #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; }

linuxbeginner
質問者

補足

 レスありがとうございます。 少し、分からないことがありますので、質問させていただきたいのですが、 if (fgets(buff_a, BUFFSIZE, fp_a) == NULL) break; ですと、行の終わりでwhileループから抜け出してしまい、 1行目しかファイルcに書き込まれないような気がします。  あと、ファイルの一方が先に終端までいった際には、もう一方のファイルの残りの行全てをファイルcに書き出したいのですが、どのようにすればいいでしょうか?  ご回答宜しくお願い致します。

関連するQ&A

専門家に質問してみよう