ファイルの中身が同じかどうか調べたい
- 評価
- クリップ 0
- VIEW 720

退会済みユーザー
複数のファイルが用意してある時、その中のファイルで中身が同じものがあるかどうかを調べるプログラムを作りたいです。 そのために、二つのファイルの中身が同じであるかどうかを調べる必要有り。
調べる対象の二つのファイルのファイル名は、コマンド行(コマンドライン)から与える。中身が同一であれば、 二つのファイルの名前を「,」で区切って並べた後に「: 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;
}
上記の正解出力となりません。
お助け頂きたく。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
0
ぱっと見ただけでも
まず、与えられた二つのファイル名について、 与えられた順にその名前を「,」で区切りながら書き出して行く。
となっていないと思います.
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
while( (cf= fgetc(f))!=EOF &&
(cg= fgetc(g))!=EOF ){
if( cf!=cg ) break;
}
この手ね、while (cf= fgetc(f))!=EOF ・・・私もCを学び始めた頃は多用したし、周りの連中もこのパターンをよく使ってました。それなりにメリットある書き方ではあるが、でもね、これを最初から書くとワケわかんなくなりがち。発想も乏しくなる。例えば今の質問者の状態(笑)。最初からこれやっちゃいけない。初心者ならなおさら。
無限ループから始めよう
繰り返しの処理を書く、とわかった時点で私流のお勧めは次のような事。
- 無限ループを書く
- 無限ループの中に、一回のループでやるべきことを並べる
- 並べることは、わかりやすい単純なことにする
- ループ脱出には
if (条件) break;
を使う
例えば上記のループは、最初こんなふうに書いてみる。
while (1) {
cf = fgetc(f);
if (cf == EOF) break;
cg = fgetc(g);
if (cg == EOF) break;
id (cf != cg) break;
}
こうしておいてから、ループの中で、何を、どのような順序にすればよいか、やり残してることはないか、じっくり考えてみる。
今回は両方から一文字ずつ読んでは比較する、それを繰り返す、ってことだ。
cf と cg の値が違うとわかった時点で不一致が確定する。一致するファイル同士なら EOF も同時に読み込めるはずだ。一方、ファイルサイズの小さい方は先に EOF が返ってきて、当然もう一方の文字と一致しないから、それも不一致と確定できる。そう考えれば「読み込んだら EOF かどうかをまず真っ先に検査」しなくてもよいことに気づくだろう。即ち、ループの中の順序は変更可能。
無限ループとはいえ、いつまでもループを回すわけじゃない。言うまでもなく EOF が返る時点までだ。ではどこで EOF の判定をすればよいか、ループの先頭が良いのかどうか・・・ま、すでにループの先頭でなくても構わないと言ったようなもの(笑)で、EOF の検査はループ後半でも可能。
そこで if (EOFが返った) break;
をループの後半に置いてみる。それがループを終了させるループ脱出条件になる(一般的にはループを終了する条件は複数ありうる)。この辺りまで来たところで、ループ脱出条件が無限ループの中で
- ループ先頭にあるなら while (条件) { ... } に書き換えられる
- ループ最後にあるなら do { ... } while (条件); に書き換えられる
- ループ脱出条件がループの途中にあるなら、break のままにしておく
経験上、ループ途中で break すると良い場合は結構ある。
そもそも、このループは何をするものか。
一致するかしないかを調べるものだ。それは EOF が返る以前でも不一致が確定する場合があり、不一致が確定した時点でループを終了して構わない。
一方、一致する場合は共に EOF が返るまで、即ちファイルの最後までループが回る。つまり、こんな格好になるだろう。
while (1) {
....
if (cf != cg) break; // 不一致確定!
// ループのどこかで EOF 判定をし、ループを脱出する
....
}
// 一致しても、不一致でも、ここを通る
ループ脱出直後の「一致しても、不一致でも、ここを通る」箇所で、どっちだったのかわからないと困るよね。当たり前だけど笑。
よくやる手はフラグ変数を使うこと。一致か不一致か、有るか無いか、表か裏か、、、といった区別をつける変数がフラグだ。ループの途中で不一致が確定する、のであるから、ループに入る前は一致するという値を持ってループを開始し、不一致が確定した時点で
フラグ = 一致;
while (1) {
....
if (cf != cg) { フラグ = 不一致; break; }
そして、ループから抜けた時点でフラグの値を調べれば一致・不一致がわかるという仕掛け。
ただ言っておきたいことがある。フラグ変数を覚えると「フラグさえあれば何でもできる!」みたいな気持ちになって、何でもかんでもフラグを使おうとするものだ(苦笑)。いったんフラグを使ってみるのは構わない。でもそこで「本当にフラグは必要か?」と自分に問うことをお勧めする。
この場合、ループが抜けた時点で
- ファイルが一致していれば、cf も cg も、どちらも値は EOF であるはず
- ファイルが不一致なら cf != cg (で break した)
と整理できて、この場合フラグ変数は不要・・・と、この辺りで大体ちゃんと動くものができてることだろう。
どなたか指摘した g= fopen(gn,"r"); が2回行われている他に、
if( !(cf==EOF && fgetc(g)==EOF) )
printf("%s and %s differ.\n"
ここの fgetc(g) は非対称で不格好。まだ整理がついてない証拠。
Enjoy !
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.32%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
y_waiwai
2019/11/14 22:30
で、しつもんはなんでしょうか
cateye
2019/11/14 23:26
data3.txt, data1.txt: IDETICAL ←これおかしくないですか?
data1.txtには先頭に空白が有るのにdata3.txt にはない(様に見える)
・・・・正確に記述して下さい・・・・
dodox86
2019/11/15 04:51 編集
コードは```C 提示したいコード ```のようにくくってください。今のままですと強力に読みづらく、これだけで回答が付きにくくなります。teratailヘルプを参照しましょう。で、肝心のコードですが、
g=fopen(gn,"r");を2回行っていておかしい上に、
> while( (cf= fgetc(f))!=EOF && (cg= fgetc(g))!=EOF ){
少なくともこれだと、2つのファイルのサイズが同じでないと意図どおり動作しないと思います。(<そのような前提条件はありませんよね)
すでにいただいた回答も含め、色々見直した方が良いかと思います。
2019/11/15 14:50
複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。