• ベストアンサー

数値の連続入力終了条件について

C言語初心者です。よろしくお願いします。 早速質問なのですが、while文を使ったscanf()関数による数値連続入力で、 ◎1---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;      while(scanf("%lf",&dt) !=EOF){   sum=sum+dt; }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎1のようにすれば、Ctrl+ZでEOFが返されたら終了とわかるのですが、今度は「0」が入力されたら処理を終了するというプログラムで、 ◎2---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;      while(scanf("%lf",&dt) !=0.0){   sum=sum+dt; }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎2のようにすると「0」が入力されても、終了せず、以下に示す◎3のように、しないと終了出来ません。 ◎3---------------------------------------------- #include<stdio.h> int main(void) {      double dt,sum=0.0;          scanf("%lf",&dt);      while(dt!=0.0){   sum=sum+dt; scanf("%lf",&dt); }   printf("合計=%f\n",sum); return 0; } ---------------------------------------------- ◎2で何故、◎1のように出来ず、◎3のようなscanf()を1回目、2回目と判定を入れなければならないか教えて下さい。

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

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

◎1の書き方では、無限ループする場合があります。 scanfは「正しく変換を行った回数、または、入力が尽きた場合にEOF」を返します。 例えば 1.2[Enter] 3.5[Enter] kkk[Enter] と入力すると、kkkを入力してEnterを押した瞬間、無限ループします。 scanfは「kkkは%lfに合わないので、0個を変換しました」と0を返し、入力バッファにkkkを残したままにします。 0はEOFとは違うので、そのままループを繰り返します。 入力バッファにはkkkが残ったまま消費されないので、次の回も、次の次の回も、scanfは永久に0を返し続けます。 そして、プログラムを止める事が出来なくなります。 ◎2の書き方でも、やはり無限ループする場合があります。 今度は「kkk」とか「@@@」とか「abcdefgh」とか、実数に変換できない物を入力する事で止まります。 しかし「Ctrl+Z」などを打ち込み「入力が尽きた状態」にすると、scanfはEOFを返します。 0はEOFとは違うので、そのままループを繰り返します。 キーボード入力は「入力が尽きた状態」のままなので、次の回も、次の次の回も、scanfは永久にEOFを返し続けます。 そして、プログラムを止める事が出来なくなります。 ◎3の書き方でも、やはり無限ループする場合があります。 今度は「0」を入力する事で止まります。 しかし「Ctrl+Z」などを打ち込み「入力が尽きた状態」にすると、scanfはEOFを返します。 この時、dtはscanfによって値を変更されませんから、dtは前回入力したままの「0以外の値」になっています。 dtが0以外では、ループを終了しません。そのままループを繰り返します。 キーボード入力は「入力が尽きた状態」のままなので、次の回も、次の次の回も、scanfは永久にEOFを返し続けます。 そして、プログラムを止める事が出来なくなります。 そう言った訳で、質問者さんの書いた3つのプログラムはどれも「無限ループする、大変に危険なプログラム」です。 下記のようなプログラムが「無限ループしない、安全なプログラム」です。 #include<stdio.h> int main(void) {   double dt,sum=0.0;   while(scanf("%lf",&dt) != 1){ // EOFや0を返したらやめる     if (dt == 0.0) // 正しい入力でも、入力が「0」ならやめる     sum=sum+dt;   }   printf("合計=%f\n",sum);   return 0; } もちろん、scanfは1個しかありません。

muffler
質問者

お礼

どれも無限ループが発生してしまうとは、まだ勉強が足りないみたいです。。安全なプログラムまで教えていただいて、ありがとうございます。 返り値などその辺りの知識を身に付け、chie65535さんの回答を参考に完璧に理解していこうと思います。

その他の回答 (4)

回答No.5

お礼を頂いてからミスに気付きました。     if (dt == 0.0) // 正しい入力でも、入力が「0」ならやめる は     if (dt == 0.0) break;// 正しい入力でも、入力が「0」ならやめる のミスです。「ループを抜けるbreak文」が抜けてました。

  • yuu_yuu
  • ベストアンサー率41% (34/81)
回答No.3

◎1 は、Ctrl+Z という特殊な操作によって、scanf が異常終了したため返却値に EOF が戻された から、式が成立してます。 一方、◎2は、0 を入力した場合の scanf は正常に終了したため、&dtに 0 が入り、戻り値には 入力要素の個数が返却されているはずです。 よって、返却値が 0 と一致しないため、終了しません。

muffler
質問者

お礼

返却値が一致しないという考えは理解できました。 戻り値などの関数はこれから学んでいくので、その後、yuu_yuuさんの回答をもう一度見てみれば、完全に理解が出来ると思います。 もっと関数について理解し努力していきます。 ありがとうございました。

  • zenigataf
  • ベストアンサー率13% (7/52)
回答No.2

scanfが実行されると、成功したという情報として0以外の数値が返されると思います。 よって、while文はどんなデータを読み込もうが無限ループしている気がします。

muffler
質問者

お礼

0以外の値が返され、一致しないという考えは何となく理解できました。 戻り値など関数については、これから学んでいくので、この事が理解できてくると思います。 ありがとうございました。

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

scanf の返り値が何を意味するのかを調べればわかります. もちろん while (scanf("%lf", &dt), dt != 0) { ... } と書くことは可能.

muffler
質問者

お礼

初心者ということで、返り値等の概念はまだ分かりませんが、これからその関数について学んでいくので、理解していこうと思います。 ありがとうございました。

関連するQ&A