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)*/

A 回答 (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に入力を浮動小数点変換したものが設定されている */
    • good
    • 0
この回答へのお礼

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

お礼日時:2002/03/04 09:15

scanf系の関数は想定外の入力に弱いので、


こういうエラー処理を考えるならまず使わないですね。

getsとatofがいいでしょう。
scanfの戻り値でもある程度はわかりますが、
多少厳密さに欠けます。
例えば,"123ABC"と入力した場合、エラーとするか、
123が入力されたとするかという違いです。

あとgetsよりもfgetsの方がバッファオーバーフローがおきなくて本当はいいのですが・・・
    • good
    • 0
この回答へのお礼

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

お礼日時:2002/03/04 07:46

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の中の条件式で全部判定させましたが、
見易いように分けた方がいいかも知れません。
    • good
    • 0
この回答へのお礼

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

お礼日時:2002/03/04 07:37

scanf()は演習用にはよいですが、アプリには使いません。


scanf()は最悪の関数ですから。

文字列として入力させ、入力された文字列が正しいか、チェックして、それを実数に変換します。

文字列入力:gets()
チェックには:isdigita()
などを使うようです。
    • good
    • 0
この回答へのお礼

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

お礼日時:2002/03/04 05:15

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qprintf("文字列\n")が円マークなんです!!斜線がでない!!

うちのノートパソコン(IBM)OSはTurbolinux Personalと、デスクトップ(NEC)OSはWindows2000でC言語のプログラミングをすると文字が変なんです。

printf("文字列\n");

と改行のエスケープシークエンス?を入力すると円マーク(\)なんです!!

右下がりの斜線のキーを押してるのに円マーク(\)しかでないんです。二つのPCどちらでやってもです。C言語のテキストでは右下がりの斜線とnで改行のエスケープシークエンス?になっているので見ていて気持ちが悪いです・・・。

ちゃんと右下がりの斜線は出せないものでしょうか。ちなみにキーボードには右下がりの斜線が書いてあります。

プログラミング上も\nで右下がりの斜線と同じ、改行の意味で理解されているらしく、ちゃんと改行されます。

でも右下がりの斜線じゃないと気持ち悪い・・・。直せませんか?

Aベストアンサー

日本語環境だと、\で正解です。
同じ意味(文字コード)です。


\(の半角)は バックスラッシュといいます。
日本語フォントでは、歴史的な原因で \ の文字コードと同じものが割り当てられていますので、日本語フォントで表示している限り、 ¥(半角)が表示されます。


歴史的背景をここで解説すると文字数足りなくなりますので。
ここ
http://ja.wikipedia.org/wiki/%5C
や、ここ
http://ja.wikipedia.org/wiki/%E5%86%86%E8%A8%98%E5%8F%B7
を読んでください。

Qprintf("\a");のアラーム音

言語:c

#include <stdio.h>

int main ( void ) {
printf("\a");
return (0);
}

上記のプログラムを実行すると、
アラーム音(?)が鳴ります。

音が出ている場所がスピーカからではなくて、
PCの本体から出ているようです。

なぜスピーカから鳴らないのでしょうか。
なぜPC本体から鳴っているのでしょうか。

Aベストアンサー

環境にもよるのですが…Windowsですか?一般的なPCの場合、
スピーカからなる宇和揺る普通のサウンドの他に、BEEP音源というのがありまして。
こちらはデバイスが違うのでPC本体から直接音が鳴ります。
# 現在では、例えばシステムの異常を通知するような時くらいしか使われないかも。
で、\aにこちらが使われるのは、多分にMS-DOS時代からの歴史的な経緯じゃないかと思います。
昔はコレでも普通でしたし、
\aは「何か音がなればいい」というものであって、どんな音を鳴らすかは別に決まってないですし、
めったに使われないので綺麗なサウンドとか必要ないと思いますし、
OSがおかしくてもなる可能性がBEEPの方が高いかもしれませんし…。

Qprintfとscanfの違いって・・・

ふとした疑問がわいたので、質問させていただきます。

なぜ、scanfの時は scanf("%d",&a)のように
アンパサンド&をつけるんでしょうか?

一方、printfだと、prinf("%d",a)のように
アンパサンド&はつけません。

どうして、両方とも関数なのに
アンパサンドをつける、つけないの区別があるんでしょうか?

プログラミングしていて、ふと思ったんですが
なぜなんでしょうか・・・?

Aベストアンサー

scanfはaという変数のある「場所」に"%d"の型で格納すると言うものです。
一方printfではaという変数の「中身」を"%d"という型で出力すると言うものです。
つまりaと表記した場合はaの「中身」を指すことになり、&aと表記された場合はaという変数のある「場所」を指すことになります。

詳しく言うと今aという変数が10と言う場所に割り当てられているとします。そして中身には5と言う数値が入っていたとします。
この場合aのある「場所」は10となり、「中身」は5となります。
&aと書いた場合は「場所」を表すことになりますので、scanfには10が渡されて、格納したい「場所」を指定しています。10と言う場所はaに割り当てられているのでaに格納されることになります。
もしscanfでaと書いてしまった場合は、5と言う数値が渡されてしまい、本来10という場所にあるaとは無関係な5と言う場所にある何かに格納されてしまいます。
これでは思ったとおりの結果にはならないはずです。

まとめるとアドレスか、中身かといえます。

Qwhileとscanfの関係について

while文中のscanf関数が意図しない動作をして困っています
簡略化したコードがこちらになります
while(1){
// view
printf("view\n");
// input
char key;
scanf("%c", &key);
// update
printf("update\n");
}

行いたい動作というのは単純で
view -> input -> update ->を繰り返したいだけなのですが
上記プログラムでは下記のような動作になってしまいます
view -> input -> update -> view -> update -> view -> input ->
偶数回目のループでは、inputが飛ばされてしまうのですが、何が原因なのかかがわかりません。

言語仕様に詳しい方、どなたかご教示ください。

環境
WindowsXP
Visual C++ 2008 ExpressEdition

Aベストアンサー

scanf()を使用していることに対しての弊害ですね。
scanf()はリターンキーの直前までの入力をキーバッファから取得します。
キーバッファにはリターンキーが残ったままとなっている為、次のscanf()でバッファに残ったものが取り込まれてしまう為に発生する問題です。
「printf("update\n");」の部分でブレークをかけて「key」の入力内容を確認すればわかりますが、偶数回目にはリターンキーのコードが取得されています。
scanf("%c", &key);
scanf( "%*[^\n]" );
のように、取得した内容以降のバッファの読み飛ばしを追加するか
scanf()以外の入力関数でを使用することで回避します。

Q改行の書き方('\n' "\n")はどっちの書き方でもいいのでしょうか?

タイトルの通りです。
↑の方法ではどっちもコンパイルできる事が分かったのですが、どっちも正しいですよね?
よろしくお願いします。

Aベストアンサー

受けて側にあわせてやる必要があります

'\n'は文字として相手が受け取る場合です
"\n"は文字列として相手が受け取る場合です

void func1( char ch );
void func2( char* str );
とあった場合 func1には '\n'で渡し fucn2は "\n"で渡します


人気Q&Aランキング

おすすめ情報