アプリ版:「スタンプのみでお礼する」機能のリリースについて

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回目と判定を入れなければならないか教えて下さい。

A 回答 (5件)

◎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個しかありません。
    • good
    • 0
この回答へのお礼

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

お礼日時:2009/01/28 08:17

お礼を頂いてからミスに気付きました。



    if (dt == 0.0) // 正しい入力でも、入力が「0」ならやめる

    if (dt == 0.0) break;// 正しい入力でも、入力が「0」ならやめる
のミスです。「ループを抜けるbreak文」が抜けてました。
    • good
    • 0

◎1 は、Ctrl+Z という特殊な操作によって、scanf が異常終了したため返却値に EOF が戻された


から、式が成立してます。

一方、◎2は、0 を入力した場合の scanf は正常に終了したため、&dtに 0 が入り、戻り値には
入力要素の個数が返却されているはずです。
よって、返却値が 0 と一致しないため、終了しません。
    • good
    • 0
この回答へのお礼

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

お礼日時:2009/01/21 02:10

scanfが実行されると、成功したという情報として0以外の数値が返されると思います。


よって、while文はどんなデータを読み込もうが無限ループしている気がします。
    • good
    • 0
この回答へのお礼

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

お礼日時:2009/01/21 02:14

scanf の返り値が何を意味するのかを調べればわかります.


もちろん
while (scanf("%lf", &dt), dt != 0) {
...
}
と書くことは可能.
    • good
    • 0
この回答へのお礼

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

お礼日時:2009/01/21 02:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!