- ベストアンサー
数値連続入力プログラムでの配列に格納される文字について
- #数値連続入力プログラムでの配列に格納される文字について
- 数値連続入力プログラムでの文字の格納方法について疑問があります。プログラムの改良により、エラー表示が正しく行われるようになったのですが、改行文字の格納状況について詳しく知りたいです。
- 入力された文字列が配列に格納される際、改行文字以外の文字列のみが正しく格納される理由を教えてください。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
>ここで疑問なのですが、例えば、 「scanfは、先頭にある空白や改行を読み飛ばしてから、指定の数値を読もうとする」ので enter enter で入れられた改行2つは、scanfが読み飛ばします。 で、scanfが最初の改行を読み飛ばした後で「a」を見付けるので、その「a」は「まだ読んで無い事にして」から、0を返します。 入力バッファには「abc」+「改行」が残っています。 次に「getsは改行まで読み込んで、読み込んだ改行を文字列の終端記号の'\0'に書き替えてから戻って来る」ので「abc\n」を読み込み、\nを\0に書き替えて「abc\0」がssの中に入ります。 ここで問題になるのが「scanfは、先頭にある空白や改行を読み飛ばしてから、指定の数値を読もうとする」と言う部分。 なのでscanfを使う限り「enterだけの入力」で「正しく入力してください」とエラー表示する事は出来ません。 その部分を修正したのが、以下のプログラムです。 #include <stdio.h> int main(void) { char ss[256]; double sum=0.0,dt; int ret; char c; char *p; for (;;) { // scanfは使わないで、とにかく1行全部をssに入力する p = gets(ss); // Ctrl+Zが入力されたらgetsはNULLを返すので終了する if (p == NULL) break; // 入力したssから、数値と、数値の直後の文字を取り出す。 ret = sscanf(ss,"%lf%c",&dt,&c); // 改行のみの入力なら「ssが空っぽ」なのでretはEOFになる。 // 数値だけの入力なら、後ろの%cが入力されないのでretは1になる。 // 数値以外の入力なら、retは0になる。 // 数値の後ろに何か余計な物があったらretは2になる。 // 数値だけ入力したかどうか調べる。 if (ret == 1) { // 数値だけ入力した。 printf("入力された数値=%f\n",dt); // 数値だけ正しく入力したので、sumにdtを足す。 sum += dt; } else { // 何も入力せずにEnterだけ押したか、数値以外を入力したか、余計な物を入力した。 // エラー表示する。 printf("正しく入力してください\n"); } } printf("合計=%f\n",sum); return 0; } で、これでOKかと言うと、そうじゃない。 この「修正版プログラム」で、以下のように入力してみよう。 1a 1b 1c 1d 1e 1f Ctrl+Z 結果は 1a 正しく入力してください 1b 正しく入力してください 1c 正しく入力してください 1d 正しく入力してください 1e 入力された数値=1.000000 1f 正しく入力してください ^Z 合計=1.000000 となる。なぜか「1e」だけ「1」として入力され「正しい入力」と判断されてる。 実は、scanfの%lfは「仮数部+e+指数部」と言う入力を許しているのだ。 例えば「120」は「1.2×10の2乗」なので、入力時に「1.2e2」と入力しても良い。 上記の「1e」は「1×10の0乗で、eの後ろの0が省略されてて、1e0と入力した」と認識されてしまう。 「10の0乗」は「1」なので「1×10の0乗」は「1×1」なので、結局は「1」になってしまう。 こういう「意図しない入力を除外したい場合」は「scanfする前に、自前で、入力した文字列が正当か調べる必要」がある。
その他の回答 (1)
- koko_u_u
- ベストアンサー率18% (216/1139)
>何故そうなるのか教えていただけると嬉しいです。 gets() の仕様です。
お礼
ご回答ありがとうございます。 >改行2つは、scanfが読み飛ばします。 >入力バッファには「abc」+「改行」が残っています。 >「getsは改行まで読み込んで、読み込んだ改行を文字列の終端記号の'\0' >に書き替えてから戻って来る」ので「abc\n」を読み込み、\nを\0に書き >替えて「abc\0」がssの中に入ります。 上記の内容、scanfは改行を読み飛ばすという事やgetsの仕様が理解できました! 修正していただいたプログラムも、ステップオーバー実行して理解できました! 簡潔なプログラムになって、とてもわかりやすっかたです。 >scanfの%lfは「仮数部+e+指数部」と言う入力を許しているのだ。 >「意図しない入力を除外したい場合」は「scanfする前に、自前で、入力 >した文字列が正当か調べる必要」がある。 以上のご回答にあるような入力を回避出来るようなプログラム作成、努力してみます。