• ベストアンサー

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

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

  • scanfに文字が入力されたときにエラー表示させる

    こんばんは.C言語勉強中です. 以下にsizeofを用いて各データタイプのサイズを表示させるプログラムを作りました.プログラム全文は下に貼付けました.これは,1-7までのいずれかの数字を入力すると,それに対応したサイズが表示されます.1-7以外の数字が入力されると,Type 1 - 7, please,と表示され,再び数字を入力出来ます.このプログラムは数字を入力している間はうまく機能していると思います. ただ,文字を入力すると無限ループに陥ってしまいます.僕は以下の scanf("%d",&typed); で10進数で読み込んで, if(typed<1 || typed >7) とすれば,文字も含めて全ての入力に対して排除できるかと思ったのですが,これではダメなようです. こういう場合,どうやって文字の入力に対するエラーを表示させるのが一般的なのでしょうか? 素人質問ですみません.よろしくお願いします. #include <stdio.h> #include <stdint.h> #include <Windows.h> int8_t main() { int typed; while(1) { while(1) { printf("Type the data type you wanna know the size of\n"); printf("char 1, short 2, int 3, long 4, long long 5, float 6, double 7: "); scanf("%d",&typed); printf("What you typed is %d\n",typed); if(typed<1 || typed >7) { printf("Type 1 - 7, please\n"); Sleep(1000); continue; } else { break; } } printf("Data size is "); switch(typed){ case 1: printf("%d\n",sizeof(char)); break; case 2: printf("%d\n",sizeof(short)); break; case 3: printf("%d\n",sizeof(int)); break; case 4: printf("%d\n",sizeof(long int)); break; case 5: printf("%d\n",sizeof(long long)); break; case 6: printf("%d\n",sizeof(float)); break; case 7: printf("%d\n",sizeof(double)); break; default: printf("Unexpected Value!\n"); break; } Sleep(2000); } return(0); }

  • ダメだ・・・分からない。while文 無限ループ&’\n’エンター後無限ループ脱出

    忙しい中失礼します。 C言語超初心者のものです。while文での表示について質問があります。 下記の’プログラム内容’はEnterキーが押されるまで、 ’k’入力後 → Enterキー → ASCII value of k is 107.  ’t’入力後 → Enterキー → ASCII value of t is 116. ・・・ のように継続させ、 何もアルファベットを記入せず、’Enterキー’のみを押した場合はループから抜け、DOS画面を終了するようにしたいのですが、それが出来ません・・・。 ’k’入力後Enterキーを押すと、’Enter a character:’の表示がなされた後、’Press any key to continue・・・’となり画面を閉じなければいけなくなります。 while文の中の()内を何とかすれば、思い通りのプログラムになる、とは思うのですが、それが考え付きません。 申し訳ありませんが、よろしければそのヒントを下さい。多分すごく簡単なことだとは思うのですが、それが出来ません。 ※私個人の考えとしては、while文の中の(scanf("%c", &ch)&&(ch!='\n'))において、’&&(ch!='\n')’をプログラム文からなくせば、Enterキーを押さない限り(’k’入力後のEnterキー除く)、何度もパソコン側から尋ねられると思ったのですが・・・。・・・うまくいかず。 プログラミング内容: #include <stdio.h> #include <stdlib.h> int main() { char ch; printf("Enter a character:\n"); while(scanf("%c", &ch)&&(ch!='\n')) { printf("ASCII value of %c is %d.\n\n", ch, ch); printf("Enter a character:\n"); } system("PAUSE"); return 0; }

  • エラー処理

    万年カレンダーを作っています。 while(1){ printf(" 西暦年>"); scanf("%d",&year); /*西暦年入力*/ printf("   月>"); scanf("%d",&month); /*月入力*/ if(year>0 && month>0 && month<13){     break; } else{ printf("正しく入力してください\n"); } 上記のように、数字のエラー処理をしたのですが、これに数字以外のモノが入力された場合のエラー処理も追加しなければなりません。

  • 関数の値(scanf)

    初心者なもので、言葉の使い方を間違っていたら申し訳ありません。いいたいことが伝わればよいのですが…。 scanfに関して疑問に思ったことがあります。経験的なことなので、正しいかわからないです。次の(1)と(2)から(3)のことが正しいか教えてください。 (1) int a; do{ printf("整数を入力してください\n"); }while(scanf("%d",&a) ==0); printf("入力した数は、%dです",a) このとき、「(いかなる整数)+(ENTER)」を入力しても、do~whileのループを抜け出す。 (2)また、上のプログラムで、継続条件式の中身を  … }while(scanf("%d",&a)!=0);  … とすると、「(いかなる整数)+(ENTER)」を入力してもループが抜け出せない。 (3)したがって(1)と(2)から、scanf()は入力するだけで、値を真(1)を返す。

  • 改行のせい(?)で入力がうまくいきません

    改行のせい(?)で入力がうまくいきません C言語でプログラムを組んでいるのですが 入力したいところが飛ばされてしまいます。 例えばプログラムの一部ですが int main(void) { char file_name[15]; char option[5]; while(1) { printf("0: Quit\n"); printf("1: Count the number of characters\n"); printf("2: Pass or fail\n"); printf("3: Prime numbers\n"); printf("Choose an option from above: "); scanf("%s", &option); if(option[0]=='1') { printf("Enter the external name of the file: "); gets(file_name); printf("The number of characters in the text file is %d.\n\n", countText(file_name)); continue; } else if (option[0]=='2') { passFail(); continue; のoptionで'1'と入力してリターンを押すと file_nameを入力する機会を与えてくれず、「ファイル名がない」と怒られて 終了してしまいます。 きっと改行のせいだと思うのですが、どうしていいのか分かりません。 最初はchar型にしてたのですがstring型にして 最初の一文字だけ見るようにしましたけどダメです。 getcharなんて使えないですよね…。 「改行 入力 LF」なんてキーワードで検索やってみたんですけど見つかりませんでした。 Windows XP, Visual C++ Version 5.0を使っています。 どなたか解決方法を教えて下さい。

  • scanfの入力形式確認について

    scanfで入力形式を%dに指定した場合、文字をタ-ミナル上で入力しても読みとばされるようで、結果 printf("please input 0 or 1.\n") while(1){ scanf("%d",&a); if(a==0 || a==1)break; printf("please input 0 or 1!\n") } といったプログラムをかいた場合、while内を永遠さまようプログラムになってしまいました。 入力を%cにしてatoiを使う以外の手法で、入力を%dに固定するかもしくは文字が入力された場合にはエラ-をはくプログラムにしたいのですが、そのような変更は可能でしょうか? 初歩的な質問で申訳ありませんが、ご教授よろしくお願いします。

  • 入力ファイルのデフォルトの設定

    下のソースは入力ファイルの内容が例えば、 1 2 3 4 5 6 7 8 の時にその内容を出力するものです。 入力ファイル名がinput.datの場合、プログラム実行後にinput.datと入力し、Enterを押します。 このプログラムにinput.datをデフォルトとし、空Enterで入力を実行できるようにしたいと考えています。 入力ファイル名がinput.datでない場合は従来通りファイル名を入力してEnterを押すようにします。 この場合、どのようにソースを変更すればよいでしょうか。お手数ですが、教えてください。よろしくお願いします。 #include <stdio.h> #include <stdlib.h> int main(){ int i,N=0,data[10]; char ifile[20]; FILE *fp; printf("input file name: "); scanf("%s",ifile); if((fp=fopen(ifile,"r"))==NULL){ fprintf(stderr,"input file error\n"); exit(1); } while(fscanf(fp,"%d",&data[N])!=EOF && N<10){ N++; } printf("Total Number of Data = %d\n",N); for(i=0;i<N;i++){ printf("%d\n",data[i]); } fclose(fp); return 0; }

  • 数値連続入力プログラムでの配列に格納される文字について

    -------------------------------------------------------- #include<stdio.h> int main(void) {    double sum=0.0;    double dt,x    int ret,n;    char ss[80];    ret=scanf("%lf",&dt);    while(1){       if(ret==1){          x=sum;          sum+=dt;          n=getchar();         if(n=='\n'){            printf("入力された数値=%f\n");            puts("");            sum=sum;         }         else{          printf("正しく入力してください\n");          puts("");          gets(ss);          sum=x;          dt=0.0;         }       }       else if(ret!=0){          gets(ss);          dt=0.0;          printf("正しく入力してください\n");          puts("");       }       else if(ret==EOF){          break;       }       ret=scanf("%lf",&dt);    }       printf("合計=%f\n",sum2);       return 0; } -------------------------------------------------------- 前回、「scanfの入力をgets関数で読み捨てることについて」というタイトルで数値連続加算のプログラムを作り、皆様からいろいろとアドバイスを受けた者です。 いろいろとプログラムを改良し、「Ctrl+Z」の入力でプログラムを終了しようとし、後、前のプログラムでは「10abc」などと打ち込んでも「10」は読み込んでしまうので、「10abc」などと打ち込んだ時点で、エラー表示をさせるようにしました。 ここで疑問なのですが、例えば、 ------- enter enter abc ------- と入力した場合、改行文字が配列ssに格納され、いろいろと複雑になってしまうのかと思ったのですが、ssにはしっかり「abc」だけが格納されていました。 以上のプログラムに不備がないかも含めて、何故そうなるのか教えていただけると嬉しいです。

  • error C2143: 構文エラー : ';' が '{' の前にありません。

    #include <stdio.h> int main(void) {   int in;   printf("20以上の数字を入力してください\n");   scanf("%d", &in);   if(in >= 20){     printf("20以上の数字です。\n");     printf("終了します\n\n");}   else if(in <= 5){     printf("5以下の数字が入力されました\n");     printf("20には程遠いです\n\n");}   else(in <= 19){     printf("20以上の数字ではありません\n");     printf("20以上の数字を入力してください\n\n");}   return 0; } C言語でVisual C++ Expressを使っています このコードでビルドすると (16) : error C2143: 構文エラー : ';' が '{' の前にありません。 と表示されてしまいます。何がいけないのでしょうか?

  • C言語の四則演算プログラムについて

    こんにちは。hayato2192といいます。 今回は、C言語についてのことを質問したいとおもいます。 MSN相談箱の質問の中で数ある四則演算プログラムに対する質問をみたのですが、僕がつくろうとしているプログラムとはまったくちがいました。 プログラムコードは以下です。 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ #include <stdio.h> main() { int d1, d2; char op; printf("START PROGRAM : Arithmetic operation\n"); printf("ENTER THE NUMBER\n"); scanf(" %d", &d1); printf("ENTER THE OPERATOR\n"); scanf(" %c", &op); switch (op) { case '+': printf("ENTER THE NUMBER\n"); scanf(" &d", &d2); printf("ANSWER IS %d\n", d1+d2); break; case '-': printf("ENTER THE NUMBER\n"); scanf(" &d", &d2); printf("ANSWER IS %d\n", d1-d2); break; case '*': printf("ENTER THE NUMBER\n"); scanf(" &d", &d2); printf("ANSWER IS %d\n", d1*d2); break; case '/': printf("ENTER THE NUMBER\n"); scanf(" &d", &d2); printf("ANSWER IS %d\n", d1/d2); break; default: printf("NO ANSWER\n"); break; } return 0; } \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ 使っている関数はscanf printf switchだけというとてもシンプルなプログラムなのです。 じっさい、このプログラムをBorlandのコンパイラでコンパイルすると、switch関数がまったく使われずに、演算子(このプログラムでいうOPERATORです)を入力するところで終了してしまいます。 どのように直せばよいのでしょうか。教えてください

専門家に質問してみよう