• ベストアンサー

scanfの入力をgets関数で読み捨てることについて

-------------------------------------- #include<stdio.h> int main(void) { double dt=0.0,sum=0.0; char ss[80]; int ret; ret=scanf("%lf",&dt); puts(""); if(ret!=1){ gets(ss); printf("数値を入力してください\n"); puts(""); } while(dt!=999){ sum=sum+dt; ret=scanf("%lf",&dt); puts(""); if(ret!=1){ gets(ss); printf("数値を入力してください\n"); puts(""); } } printf("合計=%f\n",sum); return 0; } -------------------------------------- 以上のプログラムで、入力した数値の合計を出し「999」が入力されたら終了させ、数値以外が入力されたら、gets関数で読み捨て入力を続けていくということをしたいのですが、例えば、 ◎1----------- 2 3 4 999 合計=9.000000 --------------- ◎1のように数値のみだと正しく表示されます。 次に、 ◎2-------------------- a 整数を入力してください b 整数を入力してください 2 3 999 合計=5.000000 ------------------------ ◎2のように数値以外を先に入力し、その後に数値を入力しても正しく表示されます。 次に、 ◎3------------------- 2 3 a 数値を入力してください b 数値を入力してください 999 合計=11.000000 ----------------------- ◎3のように数値を入力した後に、数値以外を入力したら正しく表示されません。 次に、 ◎4-------------------- 2 a 整数を入力してください b 整数を入力してください 3 999 合計=9.000000 ------------------------ ◎4のように数値をまず入力しその後、数値以外を入力する。その後、数値を入力して終了させても、合計値が正しく表示されません。 まだ、バッファについて完全に理解していないということもあり、何故こうなってしまうのか分かりません。 教えていただけると嬉しいです。

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

  • ベストアンサー
回答No.10

>「a」、「b」を入力した時点で、「3」はバッファ内でどうなっているのでしょうか? バッファ内には何もありません。入力バッファはgets()で捨てられています。 >正常な入力が次に行われるまで、正常に入力された値はバッファ内に残っているということでしょうか? バッファ内ではなく「dtそのもの」に「前回の値」が入ったままになっています。 実は、2も「正しく動いてないが、偶然、結果が正しい値と一致しただけ」です。 scanfは「書式と一致した入力を受け取ったら指定された変数に値を代入して、書式に一致しない入力を受け取った時点で処理を中断し、それまでに代入出来た個数を返す」と言う仕様になっています。 ◎2は double dt=0.0,sum=0.0; の初期化で「dtが0.0になっている状態」で、最初の ret=scanf("%lf",&dt); の行で「a」が入力され「dtは変更されずに0.0のまま」で if(ret!=1){ gets(ss); printf("数値を入力してください\n"); puts(""); } が実行され、バッファ「だけ」が消去されます。しかし「dtは前のまま」です。そして「aが入力され、dtが何になっているか判らないというのに」以下の while(dt!=999){ sum=sum+dt; の部分で「値が何なのか判らないdtをsumに足している」のです。 ですが「運良く、dtを0.0に初期化したまま」だったので、sumの値は変わりません。 ◎3は double dt=0.0,sum=0.0; の初期化で「dtが0.0になっている状態」で、最初の ret=scanf("%lf",&dt); で「2」が入力され、dtは2.0になります。retは1になりますから if(ret!=1){ gets(ss); printf("数値を入力してください\n"); puts(""); } は実行しません。そして while(dt!=999){ sum=sum+dt; でsumにdtが足され、sumが2.0になります。次に ret=scanf("%lf",&dt); で「3」が入力され、dtが3.0になり、retは1になります。次の if(ret!=1){ gets(ss); printf("数値を入力してください\n"); puts(""); } は実行されません。ここでwhileループを繰り返しますから while(dt!=999){ sum=sum+dt; でsumにdtが足され、sumが5.0になります。次に ret=scanf("%lf",&dt); で「a」が入力され、dtは3.0のまま、変更されません。入力は失敗してますからretは0になりますので if(ret!=1){ gets(ss); printf("数値を入力してください\n"); puts(""); } が実行されます。そして、そのままwhileループを繰り返し while(dt!=999){ sum=sum+dt; でsumにdtが足され、sumが8.0になります。「a」を入力したのでsumにdtを足してはいけないのに、足してしまっています。続いて「b」を入力した時も「dtが3.0のまま、sumにdtを足す」ので「sumが11.0」になります。 結果として「999を入力して終了させると、sumが11.0になっている」ことになります。 入力の前と後で、dtとsumの値が何になっているか、まとめてみます。 ◎1の場合 入力「2」 入力前のdt「0.0」 入力前のsum「0.0」 入力後のdt「2.0」 dtを加算後のsum「2.0」 入力「3」 入力前のdt「2.0」 入力前のsum「2.0」 入力後のdt「3.0」 dtを加算後のsum「5.0」 入力「4」 入力前のdt「3.0」 入力前のsum「5.0」 入力後のdt「4.0」 dtを加算後のsum「9.0」 入力「999」 sum「9.0」を表示 ◎2の場合 入力「a」 入力前のdt「0.0」 入力前のsum「0.0」 入力後のdt「0.0」 dtを加算後のsum「0.0」 入力「b」 入力前のdt「0.0」 入力前のsum「0.0」 入力後のdt「0.0」 dtを加算後のsum「0.0」 入力「2」 入力前のdt「0.0」 入力前のsum「0.0」 入力後のdt「2.0」 dtを加算後のsum「2.0」 入力「3」 入力前のdt「2.0」 入力前のsum「2.0」 入力後のdt「3.0」 dtを加算後のsum「5.0」 入力「999」 sum「5.0」を表示 「a」「b」入力時はsumにdtを加算してはいけないが「偶然、dtが0.0のまま」なので、影響が出なかった。影響は出なかったが、バグはバグ。 ◎3の場合 入力「2」 入力前のdt「0.0」 入力前のsum「0.0」 入力後のdt「2.0」 dtを加算後のsum「2.0」 入力「3」 入力前のdt「2.0」 入力前のsum「2.0」 入力後のdt「3.0」 dtを加算後のsum「5.0」 入力「a」 入力前のdt「3.0」 入力前のsum「5.0」 入力後のdt「3.0」 dtを加算後のsum「8.0」 入力「b」 入力前のdt「3.0」 入力前のsum「8.0」 入力後のdt「3.0」 dtを加算後のsum「11.0」 入力「999」 sum「11.0」を表示 ここで「バグの影響」がモロに出ています。 ◎4 入力「2」 入力前のdt「0.0」 入力前のsum「0.0」 入力後のdt「2.0」 dtを加算後のsum「2.0」 入力「a」 入力前のdt「2.0」 入力前のsum「2.0」 入力後のdt「2.0」 dtを加算後のsum「4.0」 入力「b」 入力前のdt「2.0」 入力前のsum「4.0」 入力後のdt「2.0」 dtを加算後のsum「6.0」 入力「3」 入力前のdt「2.0」 入力前のsum「6.0」 入力後のdt「3.0」 dtを加算後のsum「9.0」 入力「999」 sum「9.0」を表示 ここも「バグの影響」がモロに出ています。 結論は「数値以外を入力した時も、sumにdtを足しているのが悪い」のです。 バッファがどうとか、そういう問題ではありません。 以下のように修正しましょう。 #include<stdio.h> int main(void) { double dt=0.0,sum=0.0; char ss[80]; int ret; ret=scanf("%lf",&dt); puts(""); if(ret==1){ sum=sum+dt; //入力が正常な時だけsumに足す } else if(ret!=EOF){ gets(ss); printf("数値を入力してください\n"); puts(""); } while((ret!=EOF)&&(dt!=999)){ ret=scanf("%lf",&dt); puts(""); if(ret==1){ sum=sum+dt; //入力が正常な時だけsumに足す } else if(ret!=EOF){ gets(ss); printf("数値を入力してください\n"); puts(""); } } printf("合計=%f\n",sum); return 0; } あと、蛇足ですが「数字の後にEOF(Ctrl+Z)を入力したら、プログラムが永久に止まらなくなる」と言うのも修正してあります。 修正前のプログラムは 2<Enter> 3<Ctrl+Z><Enter> と入力したら「止まらなくなる」ので絶対にやってはいけません。

muffler
質問者

お礼

ご回答ありがとうございます。 各実行結果のdtの値とsumの値を詳細にご回答していただき、かなり理解できました! 修正してもらったプログラムも理解できました! 修正してもらったプログラムで、 ------------------------------------------ if(ret= =1){ sum=sum+dt; //入力が正常な時だけsumに足す } else if(ret!=EOF){ gets(ss); printf("数値を入力してください\n"); puts(""); } ------------------------------------------ 最初のifでretで「1」を判定しているので、次のelse ifで「ret= =0」としても、問題ないですかね? 後、入力で「45abcd」とした場合、%lfで「45」だけを読み取り、バッファに残された「abcd」の判定の時点でエラー表示する。というのは、「45abcd」と入力した時点で、「45」を読み込まず、エラー表示するということは出来ないのですかね? お答えいただければ嬉しいです。

その他の回答 (14)

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.4

#3さん >処理系が不明なので rewind(stdin); は不可>#2 お言葉ですが、rewindはれっきとした標準関数に属します。 今回の仕様を満たすために使用することは、全く問題ありません。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

処理系が不明なので rewind(stdin); は不可>#2. 代わりに int ch; を定義してから while ((ch = getchar()) != '\n' && ch != EOF); くらい.

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.2

scanfの入力(結果)をgetsで読み捨てる、というのが どういうことを指しているのか、どうもピンと来ません。 #include <stdio.h> int main(void) { double dt, sum = 0; while (1) { printf("数値を入力してください(999で終了)\n"); if (scanf("%lf", &dt) == 1) { if (dt != 999) { sum += dt; } else { break; } } else { printf("数値以外を入力しましたね。\n"); rewind(stdin); } } printf("合計=%f\n", sum); return 0; }

muffler
質問者

お礼

ご回答ありがとうございます。 rewind関数を参考書で見てみたのですが、初心者なため、どうも使い方が理解できませんでした。すいません。 ---------------------------- #include<stdio.h> int main() { int n=0; int ret; char ss[80]; while(n==0){ printf("n="); ret=scanf("%d",&n); if(ret!=1){ gets(ss); } } return 0; } ---------------------------- 以上のプログラムが参考書にあり、整数以外の入力があった場合は、バッファ内から消す?(参考書にはバッファ内に残したデータを読み捨てると書いてありました)というものでした。 これを、数値の連続加算に応用しようと思いました。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

加算処理の方法がまずいためでしょう while( dt!=999 ) {   // ここで加算処理をしているが   // 文字など数値以外が入力された場合にも   // 前回の正常に得られたdtを加算している   sum += dt;   ret = scanf( "%lf", &dt )   if ( ret != 1 ) {     gets(ss);     printf("数値を入力してください\n");     puts("");     // ここで失敗したのだからdtをリセットする     dt = 0.0;   } }

muffler
質問者

お礼

ご回答ありがとうございます。 >前回の正常に得られたdtを加算している 以上のご回答というようになっていると分かりました。 例えば、実行結果◎3で「a」、「b」を入力しgetsでバッファ内から消しても、「3」はバッファに残っているということですかね? 「a」、「b」を入力した時点で、「3」はバッファ内でどうなっているのでしょうか? 正常な入力が次に行われるまで、正常に入力された値はバッファ内に残っているということでしょうか? 重ね重ね質問になってしまいましたが、ご回答いただけると嬉しいです。

関連するQ&A