• ベストアンサー

入力エラーの処理について。

Cプログラム初心者です。 例えば、floatの名前をlengthとして、scanfでユーザーに入力させるとします。その時ユーザが間違えて数字ではなく文字を入力した場合、その後のprintfの内容がループしてしまいます。どうしたら、ユーザーが間違えて入力したときに、入力ミスを伝え、もう一回入力をしてもらうことができるプログラムが作れるでしょうか。 以下がエラー処理をする前のプログラムの一部なのですが、、、。 float length; printf("Enter length of the room in metre and press enter.\n"); scanf("%f", &length); while (length>300) { printf("This programme only caluculate length under 300m.\n"); printf("Please re-enter the length in metre and press enter.\n"); scanf("%f", &length); }/*End of while (length)*/

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

  • ベストアンサー
  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.4

どのレベルまでのエラーチェックが必要かが不明ですが… 私ならfgets()->strtod()という手順を踏みます。 ・scanf()は入力を消費しない scanf()はエラーを返したときに入力内容を消去しません。 結果、いとも簡単に無限ループに陥ります。 エラー派生時には入力バッファのフラッシュをする必要があります。 ・gets()は入力文字数を制限できない gets()は文字列入力関数ですが、入力文字数を制限する機能がありません。 結果、想定しない文字数を入力される可能性があります。 これは、scanf()で%sを使ったときも同じです。 (sanf()の場合は回避法アリ) ・atof()は変換不能文字を報告しない atof()はエラーを報告する手段をもちません。 入力 出力 0.0  0.0 abc  0,0 1.0  1.0 1.b  1.0 abcや1.bという数値はありません。これらはエラーのはずですが、atof()にエラー報告の機能が無いために「変換可能だった文字だけを変換した結果(1.b→1.0)または、0.0(abc→0.0)」が返されます。 char *fgets()は入力文字の最大数を制限できます。 fgets(char *入力文字列用の配列,int 入力可能文字数+1,stdin); 入力可能文字数+1なので単純に配列のよう素数を指定すればオッケーです。 (入力文字の最後に'\0'が付加されるため「入力可能文字数+1」を指定します) キーボード入力を受け取る場合最後の引数をstdinとします。 strtod()は変換不能文字を発見したときに、その文字のアドレスを報告します。 結果、1.bやabcなどという「数字として認識不能な並び」を発見できます。 double strtod(char *変換する文字列,char **変換不能文字のアドレス); キーボード入力の場合の例) double len ; char str[10], *trm ; if (fgets(str, sizeof(str), stdin) == NULL){ /* 9文字以内の文字列をキーボードから入力 */ /* fgets()がNULLを返したときは"入力無し”かエラー */ エラー処理 } len = strtod(str, &trm) ; /* 文字列→浮動小数点変換 */ if (trm != NULL && (*trm != '\0' || *trm != '\n')) { /* 変換不能文字が'\0'か改行なら入力は数値、それ以外なら数値以外の入力 */ printf("数値以外が入力された:%s", str) ; エラー処理 } /* lenに入力を浮動小数点変換したものが設定されている */

lindamarie
質問者

お礼

アドバイスありがとうございます。大変複雑な内容をわかりやすく、砕いて説明していただいて感謝しております。まだ始めたばかりですが、ひとつ、ひとつの関数が持つ利点、マイナス点を理解しながら勉強を続けたいと思います。 ありがとうございました。

その他の回答 (3)

  • terra5
  • ベストアンサー率34% (574/1662)
回答No.3

scanf系の関数は想定外の入力に弱いので、 こういうエラー処理を考えるならまず使わないですね。 getsとatofがいいでしょう。 scanfの戻り値でもある程度はわかりますが、 多少厳密さに欠けます。 例えば,"123ABC"と入力した場合、エラーとするか、 123が入力されたとするかという違いです。 あとgetsよりもfgetsの方がバッファオーバーフローがおきなくて本当はいいのですが・・・

lindamarie
質問者

お礼

早速アドバイス頂きありがとうございます。初心者だと、どうしてもscanfを最初に習うので、数字=scanfなんて思ってしまいがちなんですが、実際には文字入力というのが入力エラーを抑える働きとなるんですね。初心者だと考え付かない、発想です。勉強になりました。ありがとうございました。

  • Fooky
  • ベストアンサー率71% (59/82)
回答No.2

scanf()の戻り値を使えば良いんでは? scanf()系の関数は代入に成功した変数の 数を返します。ですから、 float length; do{ printf("Enter length of the room in metre (<= 300m) and press enter.\n"); } while( scanf("%f", &length) < 1 || length > 300.0f || length < 0.0f); 面倒臭がりなのでwhileの中の条件式で全部判定させましたが、 見易いように分けた方がいいかも知れません。

lindamarie
質問者

お礼

早速アドバイス頂き、ありがとうございます。試してみます!

  • brogie
  • ベストアンサー率33% (131/392)
回答No.1

scanf()は演習用にはよいですが、アプリには使いません。 scanf()は最悪の関数ですから。 文字列として入力させ、入力された文字列が正しいか、チェックして、それを実数に変換します。 文字列入力:gets() チェックには:isdigita() などを使うようです。

lindamarie
質問者

お礼

早速アドバイス頂きありがとうございます。scanfは使わないほうがいいんですね。数字が入力できるから、、という単純な理由でscanfを使ってたんですが。エラーの時に大きな落とし穴と変わるんですね。貴重なアドバイスありがとうございました。

関連するQ&A