質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

1354閲覧

ファイル出力結果がダブってしまう

mn6262

総合スコア2

C

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

ファイル

ファイルとは、文字列に基づいた名前又はパスからアクセスすることができる、任意の情報のブロック又は情報を格納するためのリソースです。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2020/05/06 16:06

編集2020/05/06 16:33

前提・実現したいこと

既存のファイルからデータを読み取って、合計点と合否を出し、その結果を別のファイルに出力したいです。

発生している問題・エラーメッセージ

既存のファイル(kison.data)に入っているデータから合計・合否を追加したものを別のファイル(betu.data)に出力しようとしたのですが、うまくいきません。
$ cat kison.data
1 22 23
2 55 78
3 89 90

$ cat betu.data
1 22 23 45 不合格
2 55 78 133 合格
3 89 90 179 合格
3 89 90 179 合格

のように最後がおかしくなってしまいます。。。

該当のソースコード

include <stdio.h>

int main(void){

FILE *fp_r,*fp_w;
int eng,math,num,sum;

if((fp_r=fopen("kison.data","r"))==NULL){
printf("ファイルを開けません\n");
}
else if((fp_w=fopen("betu.data","w"))==NULL){
}else{
while( !feof(fp_r)){
fscanf(fp_r,"%d%d%d",&num,&eng,&math);
sum=eng+math;
if(sum>=120){
fprintf(fp_w,"%d %d %d %d 合格 \n",num,eng,math,sum);
}else{
fprintf(fp_w,"%d %d %d %d 不合格 \n",num,eng,math,sum);
}
}
fclose(fp_w);
fclose(fp_r);
}

return 0;
}

試したこと

1つ目のif文でNULLが出た時にプログラムが終了していないことに気づいて、betu.dataを開くif文をelse if文に書き換えたとたんにこの現象が現れました。
なので、タップミスか何かでループ本体を触ってしまったのかと思い、書き換える前に戻してみたりもしましたが、一向に直りませんでした。
自分でもどうしてこうなるのか本当にわからなくて、行き詰っています。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答3

0

ベストアンサー

feof の使い方を間違っているからです。

feof はこれより前の入力関数が、
ファイルの終わりに達してエラーになったことを示すものです。

feof(fp_r) が 0、すなわち !feof(fp_r) が 1だからといって
次の fscanf がエラーにならないことを保証するものではありません。

fscanf で 3行目のデータまで読めても、まだ feof は 0 のままです。
4回目の fscanf は失敗するのですが、それはチェックしていないので
3回目のデータをそのまま出力しています。

修正方法は

C

1 while (fscanf(fp_r, "%d%d%d", &num, &eng, &math) == 3) {

または、

C

1 while (1) { 2 fscanf(fp_r, "%d%d%d", &num, &eng, &math); 3 if (feof(fp_r)) break;

feof の間違った使い方の例を挙げます。

C

1 int c; 2 while (!feof(fp)) { 3 c = fgetc(fp); 4 putchar(c); 5 } 6

1文字余計に出力されてしまいます。
たいていの場合最後の文字は改行文字なので気が付かないことが多い。

C

1 char buf[1024]; 2 while (!feof(fp)) { 3 fgets(buf, sizeof buf, fp); 4 fputs(buf, stdout); 5 }

最後の行が 2つ出てしまいます。

投稿2020/05/06 16:58

kazuma-s

総合スコア8224

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

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

mn6262

2020/05/06 17:04

回答ありがとうございました。 C言語を習いはじめたばかりで、勉強不足でした。。 いただいたアドバイスを参考にしながら精進していきたいと思います。
guest

0

1 22 23
2 55 78
3 89 90

の後改行を入れているんじゃないですか?
改行後の行を読み込んでも EOF にはならないので、
fscanf(fp_r,"%d%d%d",&num,&eng,&math);
の返却値が 0 になっているはずです。

きちんと scanf の返却値をチェックして、
それの対処できるように書いてないから、
そんなことになるんですよ。

まあ、
1 22 23
2 55 78
3 89 90[EOF]
みたいにしてもいいとは思いますけど。

投稿2020/05/06 16:40

編集2020/05/06 16:43
PingHermit

総合スコア478

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

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

mn6262

2020/05/06 17:07

回答ありがとうございました。
guest

0

再現しません。
こんな出力が得られました。

1 22 23 45 不合格 2 55 78 133 合格 3 89 90 179 合格 3 89 90 179 合格

投稿2020/05/06 16:14

episteme

総合スコア16614

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

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

mn6262

2020/05/06 16:22

すみません、合否を書き忘れていました。。。 実際は私もそのように合否が出ます。 最後の3番が二回続いてしまうのはなぜなのか、よろしければご教授いただければ幸いです。
episteme

2020/05/07 00:40

ソッチか、ごめん。 他の回答にもあるとおり、while ( ファイルの終わりじゃない ) { 読んでなんかする } じゃダメなんです。 while ( 読むことができた ) { なんかする } じゃないと。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問