アプリ版:「スタンプのみでお礼する」機能のリリースについて

c言語  2つのファイルを行ごとに読み込むプログラミング

0.txt と 1.txt という2つのテキストフォルダがあり

0.txt の中身は
a a
b b

1.txt の中身は
c c
d d

というものとします。

これら2つのフォルダを読み込むとき
まず1つのフォルダの1行目(a a)を表示し
他方の1行目(c c) 2行目(d d)を表示させて
続いて1つのフォルダの2行目(b b)を表示し
他方の1行目(c c) 2行目(d d)を表示させたいのです。
つまり実行結果が

a a
c c
a a
d d
b b  ←理想の実行結果です
c c
b b
d d

となるようにしたいのですが

#include <stdio.h>
#include <stdlib.h>
#define STR_MAX 256
int main(void)
{
FILE *fp, *fp2;
int i, j, k;
char buf[STR_MAX];
char buf2[STR_MAX];

fp = fopen("0.txt", "r");
fp2 = fopen("1.txt", "r");

if (fp == NULL && fp2 == NULL){
printf("\n");
}

while(fgets(buf, STR_MAX, fp) != NULL){
while(fgets(buf2, STR_MAX, fp2) != NULL){
printf("%s%s", buf,buf2);
}
printf("\n");
}
fclose(fp);
fclose(fp2);
return 0;
}

このプログラミングの実行結果は

a a
c c
a a
d d

となり、0.txtの2行目(b b)は表示されません。
おそらく while 文 を2重にすることで
不具合が起きているのだと思うのですが
色々と調べた結果、これ以外に
プログラミングが思いつきません。
私の理想の実行結果にするためには
どこを訂正させると良いのでしょうか?
恐れ入りますが ご回答 どうかよろしくお願いいたします。

A 回答 (5件)

単純に 0.txt を一行読んで 1.txt を全て書き出すと考えます。



内側の while は一回働けば 1.txt をすべて読み込んでいますから、外側の while の二回目以降は EOF で働きません。

fgets関数をもう一度考え直してください。

内側の while でファイルの先頭から読み込ませる一番簡単な方法は、オープン/クローズを繰り返す方法です。

骨格だけですが。

fp = fopen("0.txt", "r");
while(fgets(buf, STR_MAX, fp) != NULL){
 fp2 = fopen("1.txt", "r");
 while(fgets(buf2, STR_MAX, fp2) != NULL){
  printf("%s%s", buf,buf2);
 }
 fclose(fp2);
}
fclose(fp);
    • good
    • 0
この回答へのお礼

ありがとうございます。
実行結果は見事
私の理想通りになりました。
おっしゃる通りでfgets関数を考え直すべきだと思いました。

更に質問なのですが

たとえば 先ほどの例として出したテキストファイル 
1.txt の中身を

a a
d d

としておなじ動作をおこなうとき

buf,buf2 が等しい時が(buf,buf2=a a)存在するので

if(buf == buf2){
printf("%s%s", buf,buf2);
}

とすれば、
実行結果が
a a
a a

と表示されると思ったのですが
何も表示されません。
buf = a a buf2 = a a
だとしても
if(buf == buf2)
は使えないのでしょうか?

お礼日時:2010/10/26 22:34

すみません。



> fgets関数をもう一度考え直してください

これは「考え直す」でなく「調べなおす」でしたね。

charの比較はstrcmp関数を使います。

strcmp関数を調べてみてください。

if(strcmp(buf,buf2)) かな
    • good
    • 0
この回答へのお礼

strcmp を調べた結果
if(strcmp(buf , buf2) == 0) でできる事がわかりました。
応用も何とか出来そうな気がします。
初心者の私でも分かりやすく理解出来るような解答を
本当にありがとうございます。

お礼日時:2010/10/26 23:56

すみません。

仕様を勘違いしていました。


ファイルは基本的に、読み書きしたら、その位置のままです。
なので、最初から読み直す、といった、位置を変更したい場合はfseek関数やrewind関数を使います。
今回は先頭に戻すので、rewind関数が楽でしょう。

while(fgets(buf, STR_MAX, fp) != NULL){
rewind(fp2); /* 追加 */
while(fgets(buf2, STR_MAX, fp2) != NULL){


ただ、この方法は毎回ファイルを読み込むので(キャッシュで多少早くなる可能性はありますが)効率は悪いです。
ファイルサイズが小さく、メモリに余裕があるのなら、予め全部読み込んでおいて、対応する行だけ表示する、というのがいいのですが。

# 例によって、 Perlとかだと簡単だよなぁ、と思います。
    • good
    • 0

2つのテキスト「ファイル」の中身は、


各々2行ずつで固定ですか?

2以外の行数の場合も考える必要がありますか?

この回答への補足

質問に出したテキストファイルは
あくまで例でして
本来 私がやろうとしているものは
ファイルの中の行数は未知数という状況で
そのファイルを最後の行まで表示させたいというものです。
しかもファイルによって行数が異ってもできるような
プログラミングを考えています。

なので2以外の行数の場合も考える必要があります。

補足日時:2010/10/26 22:21
    • good
    • 0

whileに限らず、二重ループというのは、


外側1回目
 内側1回目
 内側2回目
 内側3回目
...
 内側最後
外側2回目
 内側2-1回目
 内側2-2回目
 内側2-3回目
...
 内側2-最後
外側3回目
...
というようにループするものです。


考え方ですが。

まず、「1回」で行う処理は何かを考えましょう。
今回のなら
{
0.txtを1行読み込んで、(読み込めたなら)表示する
1.txtを1行読み込んで、(読み込めたなら)表示する
}
というもののはずです。

次に、どんな風に繰り返すのかを考えます。
今回は「先頭行から最終行まで」ですよね。
順番に並んでいて、しかも1方向だけです。ということは、ループも1重で済むということです。


あとは、実装方法はいろいろあります。
・無限ループを作って、終了条件になったらbreakで抜ける。
・終了するかどうかのフラグ用の変数でループを制御する。
等々.
両ファイルの行数が違う場合とかエラーがあったときとかを考えると、ちょっと複雑になります。

両ファイルの行数が同じ場合で、エラー処理とか考えなければ
> while(fgets(buf2, STR_MAX, fp2) != NULL){
これを
> if(fgets(buf2, STR_MAX, fp2) != NULL){
こうすると、とりあえずは動作します。どうしてそうなるかは、よく考えてみてください。



あとは別件ですが。
> 0.txt と 1.txt という2つのテキストフォルダがあり
用語を誤解されています。
こういうものは「ファイル」といいます。
「フォルダ」というのは複数のファイルをまとめておける「ファイルの入れ物」です。
ファイルとフォルダとでは、プログラムの方法も変わってきます。今回は例があったので「ファイル」の誤用だとわかりましたが、単独でフォルダ/ファイルと言われると、相手に正しく伝わりません。

> if (fp == NULL && fp2 == NULL){
and条件とor条件は理解していますか?
&& は 両方成立つときに真となる「and条件」です。
fopenで失敗したときの戻り値がNULLなので、このif文は「 0.txtも1.txtもfopenに失敗したとき」と言う意味になります。
「0.txtだけ失敗した」や「1.txtだけ失敗した」場合にはこのif文は成り立ちません。

また、エラー処理をしているのかと思えば
> printf("\n");
と、改行文字を表示しているだけです。何を意図しているのでしょうか?

> }
> printf("\n");
> }
> fclose(fp);
> fclose(fp2);

ここのprintfは期待しているものですか?
元の例では、1.txtが終ったときに、私のwhile→ifの変更では2行置きに改行が表示されます。
1.txtには行末の改行文字があるので、ただ継げるだけなら必要無いのではないでしょうか。
    • good
    • 0
この回答へのお礼

c言語はまだかなりの初心者でして
質問するのも難しかったのですが
私の誤りのあった質問の意図を理解していただき
ありがとうございます。

ご回答の内容を参考に
いろいろな方法を考えてみたいと思います。

お礼日時:2010/10/26 22:12

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています