🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

2回答

3146閲覧

ファイルの中身が同じかどうか調べたい

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/11/14 13:24

編集2020/02/04 05:01

複数のファイルが用意してある時、その中のファイルで中身が同じものがあるかどうかを調べるプログラムを作りたいです。 そのために、二つのファイルの中身が同じであるかどうかを調べる必要有り。
調べる対象の二つのファイルのファイル名は、コマンド行(コマンドライン)から与える。中身が同一であれば、 二つのファイルの名前を「,」で区切って並べた後に「: IDENTICAL」と出力し、 そうでなければ「: DIFFERENT」と出力するようにする。
まず、与えられた二つのファイル名について、 与えられた順にその名前を「,」で区切りながら書き出して行く。このとき合わせてそのファイルが開けることを確認する。 どちらかが開けないとわかった時には、その時点でそのファイル名の直後に「: can't open.」と書き出して改行をした上で実行を終了 ( return 0; )する。この結果、1番目のファイル名でファイルが開けなかったときは最初のファイル名の直後に「: can't open.」が続くことになり、2番目のファイル名でファイルが開けなかったときは「,」で区切られて2つのファイル名が並び、その2番目のファイル名の直後に「: can't open.」が並ぶことになる。
■つぎのファイル群が実行環境に用意されているとします
ファイル名    内容
data1.txt   ABCD EFG
data2.txt ABCD EfG
data3.txt ABCD EFG
■コマンドライン入力
data1.txt data2.txt
正解出力
data1.txt, data2.txt: DIFFERENT
■コマンドライン入力
data3.txt data1.txt
正解出力
data3.txt, data1.txt: IDETICAL
■コマンドライン入力
data4.txt data1.txt
正解出力
data4.txt: can't open.
■コマンドライン入力
data3.txt data1.c
正解出力
data3.txt, data1.c: can't open.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){

#define fn "data1.txt"
#define gn "data2.txt"
FILE *f, *g;
f= fopen(fn, "r"); g= fopen(gn,"r");

if( f==NULL){
printf("NG:%s\n",fn); exit(-1);
}
g= fopen(gn, "r");
if( g==NULL){
printf("NG:%s\n",gn); exit(-1);
}
int cf, cg;

while( (cf= fgetc(f))!=EOF &&
(cg= fgetc(g))!=EOF ){
if( cf!=cg ) break;
}
if( !(cf==EOF && fgetc(g)==EOF) )
printf("%s and %s differ.\n", fn,gn);
fclose(f); fclose(g);

return 0;

}

上記の正解出力となりません。
お助け頂きたく。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/11/14 13:30

で、しつもんはなんでしょうか
cateye

2019/11/14 14:26

data3.txt, data1.txt: IDETICAL ←これおかしくないですか? data1.txtには先頭に空白が有るのにdata3.txt にはない(様に見える) ・・・・正確に記述して下さい・・・・
dodox86

2019/11/14 19:53 編集

コードは```C 提示したいコード ```のようにくくってください。今のままですと強力に読みづらく、これだけで回答が付きにくくなります。teratailヘルプを参照しましょう。で、肝心のコードですが、 g=fopen(gn,"r");を2回行っていておかしい上に、 > while( (cf= fgetc(f))!=EOF && (cg= fgetc(g))!=EOF ){ 少なくともこれだと、2つのファイルのサイズが同じでないと意図どおり動作しないと思います。(<そのような前提条件はありませんよね) すでにいただいた回答も含め、色々見直した方が良いかと思います。
guest

回答2

0

C

1 while( (cf= fgetc(f))!=EOF && 2 (cg= fgetc(g))!=EOF ){ 3 if( cf!=cg ) break; 4 }

この手ね、while (cf= fgetc(f))!=EOF ・・・私もCを学び始めた頃は多用したし、周りの連中もこのパターンをよく使ってました。それなりにメリットある書き方ではあるが、でもね、これを最初から書くとワケわかんなくなりがち。発想も乏しくなる。例えば今の質問者の状態(笑)。最初からこれやっちゃいけない。初心者ならなおさら。

無限ループから始めよう

繰り返しの処理を書く、とわかった時点で私流のお勧めは次のような事。

  • 無限ループを書く
  • 無限ループの中に、一回のループでやるべきことを並べる
  • 並べることは、わかりやすい単純なことにする
  • ループ脱出には if (条件) break; を使う

例えば上記のループは、最初こんなふうに書いてみる。

C

1 while (1) { 2 cf = fgetc(f); 3 if (cf == EOF) break; 4 5 cg = fgetc(g); 6 if (cg == EOF) break; 7 8 id (cf != cg) break; 9 }

こうしておいてから、ループの中で、何を、どのような順序にすればよいか、やり残してることはないか、じっくり考えてみる。

今回は両方から一文字ずつ読んでは比較する、それを繰り返す、ってことだ。
cf と cg の値が違うとわかった時点で不一致が確定する。一致するファイル同士なら EOF も同時に読み込めるはずだ。一方、ファイルサイズの小さい方は先に EOF が返ってきて、当然もう一方の文字と一致しないから、それも不一致と確定できる。そう考えれば「読み込んだら EOF かどうかをまず真っ先に検査」しなくてもよいことに気づくだろう。即ち、ループの中の順序は変更可能。

無限ループとはいえ、いつまでもループを回すわけじゃない。言うまでもなく EOF が返る時点までだ。ではどこで EOF の判定をすればよいか、ループの先頭が良いのかどうか・・・ま、すでにループの先頭でなくても構わないと言ったようなもの(笑)で、EOF の検査はループ後半でも可能。

そこでif (EOFが返った) break; をループの後半に置いてみる。それがループを終了させるループ脱出条件になる(一般的にはループを終了する条件は複数ありうる)。この辺りまで来たところで、ループ脱出条件が無限ループの中で

  • ループ先頭にあるなら while (条件) { ... } に書き換えられる
  • ループ最後にあるなら do { ... } while (条件); に書き換えられる
  • ループ脱出条件がループの途中にあるなら、break のままにしておく

経験上、ループ途中で break すると良い場合は結構ある。

そもそも、このループは何をするものか。
一致するかしないかを調べるものだ。それは EOF が返る以前でも不一致が確定する場合があり、不一致が確定した時点でループを終了して構わない。
一方、一致する場合は共に EOF が返るまで、即ちファイルの最後までループが回る。つまり、こんな格好になるだろう。

C

1 while (1) { 2 .... 3 if (cf != cg) break; // 不一致確定! 4 // ループのどこかで EOF 判定をし、ループを脱出する 5 .... 6 } 7 // 一致しても、不一致でも、ここを通る

ループ脱出直後の「一致しても、不一致でも、ここを通る」箇所で、どっちだったのかわからないと困るよね。当たり前だけど笑。
よくやる手はフラグ変数を使うこと。一致か不一致か、有るか無いか、表か裏か、、、といった区別をつける変数がフラグだ。ループの途中で不一致が確定する、のであるから、ループに入る前は一致するという値を持ってループを開始し、不一致が確定した時点で

C

1 フラグ = 一致; 2 while (1) { 3 .... 4 if (cf != cg) { フラグ = 不一致; break; }

そして、ループから抜けた時点でフラグの値を調べれば一致・不一致がわかるという仕掛け。

ただ言っておきたいことがある。フラグ変数を覚えると「フラグさえあれば何でもできる!」みたいな気持ちになって、何でもかんでもフラグを使おうとするものだ(苦笑)。いったんフラグを使ってみるのは構わない。でもそこで**「本当にフラグは必要か?」と自分に問う**ことをお勧めする。
この場合、ループが抜けた時点で

  • ファイルが一致していれば、cf も cg も、どちらも値は EOF であるはず
  • ファイルが不一致なら cf != cg (で break した)

と整理できて、この場合フラグ変数は不要・・・と、この辺りで大体ちゃんと動くものができてることだろう。

どなたか指摘した g= fopen(gn,"r"); が2回行われている他に、

C

1 if( !(cf==EOF && fgetc(g)==EOF) ) 2 printf("%s and %s differ.\n"

ここの fgetc(g) は非対称で不格好。まだ整理がついてない証拠。

Enjoy !

投稿2019/11/15 02:16

編集2019/11/15 02:25
rubato6809

総合スコア1382

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ぱっと見ただけでも

まず、与えられた二つのファイル名について、 与えられた順にその名前を「,」で区切りながら書き出して行く。

となっていないと思います.

投稿2019/11/14 15:43

jimbe

総合スコア13201

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問