web-dev-qa-db-ja.com

C:複数のscanfの1つのscanfの値を入力すると、2番目のscanfがスキップされます

次のコードブロックがあります(ロジックは宿題の一部であるため、機能は省略されています)。

#include <stdio.h>

int main()
{
    char c = 'q';
    int size; 

    printf("\nShape (l/s/t):");
    scanf("%c",&c);

    printf("Length:"); 
    scanf("%d",&size);

    while(c!='q')
    {
        switch(c)
        {
            case 'l': line(size); break; 
            case 's': square(size); break;
            case 't': triangle(size); break; 
        }


        printf("\nShape (l/s/t):");
        scanf("%c",&c);

        printf("\nLength:"); 
        scanf("%d",&size);
    }

    return 0; 
}

最初の2つのScanfの動作は素晴らしいです。whileループに入ると問題ありません。新しいシェイプ文字を入力するように求められたときに、代わりにprintfにジャンプするという問題があります。長さを指定し、そこからcharの入力を受け取り、その後ループの次の反復で小数を待ちます。

ループ前の反復:

Scanf:シェイプ。よく働く
Scanf:長さ。問題ない

ループ1。

Scanf:シェイプ。これをスキップします
Scanf:長さ。問題は、このscanfがshape charにマッピングされることです。

ループ2
Scanf:シェイプ。これをスキップします
Scanf:長さ。問題、このscanfは現在サイズintにマップされます。

なぜこれをしているのですか?

20
Snow_Mac

scanf("%c")は、から改行文字を読み取ります ENTER キー。

たとえば、_15_と入力すると、_1_、_5_と入力してから、 ENTER キー。したがって、入力バッファには3つの文字があります。 scanf("%d")は_1_および_5_を読み取り、それらを数値_15_として解釈しますが、改行文字はまだ入力バッファーにあります。 scanf("%c")はすぐにこの改行文字を読み取り、プログラムは次のscanf("%d")に進み、数字が入力されるのを待ちます。

通常のアドバイスは、入力行全体をfgetsで読み取り、各行の内容を個別のステップで解釈することです。差し迫った問題に対するより簡単な解決策は、各getchar()の後にscanf("%d")を追加することです。

基本的な問題は、scanf()がバッファー内の数値の後に改行を残し、次のパスで_%c_でそれを読み取ることです。実際、これはscanf();を使用しない理由の良いデモンストレーションです。ラインリーダー(fgets()など)とsscanf()を使用します。制御が簡単です。

おそらく、フォーマット文字列に_" %c"_の代わりに_"%c"_を使用することで、それを救うことができます。空白を使用すると、scanf()は文字を読み取る前に空白(改行を含む)をスキップします。

しかし、長い目で見ればscanf()fscanf()を放棄し、fgets()または同等の機能に加えてsscanf()を使用する方が簡単です。それ以外はすべて、エラー報告は、scanf()が失敗した後に残されたドリブルではなく、文字列全体を処理する方がはるかに簡単です。

常に、scanf()から変換された値を取得することも確認する必要があります。入力は失敗します—日常的で恐ろしいです。あなたがチェックしなかったのであなたのプログラムを破壊させないでください。

19

機能を使用する

void seek_to_next_line( void )
{
    int c;
    while( (c = fgetc( stdin )) != EOF && c != '\n' );
}

入力バッファをクリアします。

6
noMAD

Scanfにスペースを追加してみてください。

_scanf(" %d", &var);
//     ^
//   there
_

これにより、scanf()は整数と一致する前にすべての空白を破棄します。

5
Jon Z.

'\n'文字は、scanfの最初の呼び出しが完了した後も入力ストリームに残っているため、scanf()の2番目の呼び出しでそれを読み取ります。getchar()を使用します。

2
Gargi Srinivas

シェイプを入力してEnterキーを押すと、シェイプは最初のscanfによって消費されますが、ENTERは消費されません! 2番目のscanfは数字を予期しているため、空白と見なされるためENTERはスキップされ、scanfは有効な入力(数字)を待機しますが、これもENTERで終了します。数字は消費されますが、ENTERは消費されないため、while内の最初のscanfはそれを使用し、形状プロンプトはスキップされます...このプロセスが繰り返されます。 Enterキーを処理するには、scanfsに別の%cを追加する必要があります。これがお役に立てば幸いです!

1
guga

scanf("%c%*c", &c);を使用して2文字を読み取り、最後の1文字を無視することもできます(この場合は '\ n')

0
Byeonggon Lee