10

ここで、私は受け入れられた答えでこの声明を見ました:

ほとんどの変換指定子は、改行を含む先頭の空白をスキップしますが、スキップ%cしません。

私にとって、この異なる振る舞いの下での論理的根拠は明確ではありません、私は均一なものを期待していました(例えば、常にスキップするか、決してしない)。

私は次のようなCコードでこの種の問題に遭遇しました:

#include "stdio.h"

int main(void){

    char ch;
    int actualNum;

    printf("Insert a number: ");
    scanf("%d", &actualNum);
    // getchar();

    printf("Insert a character: ");
    scanf("%c", &ch);

    return 0;
}

2つscanfのsを交換すると、問題と(コメント付き)が解決されます。getcharそうしないと、最初の挿入のが2番目の'\n'挿入によって消費されます。LinuxとWindowsの両方でgccでテストしましたが、動作は同じです。scanf%c

gcc(GCC)4.7.2 20120921(Red Hat 4.7.2-2)
Copyright(C)2012 Free Software Foundation、Inc.
これはフリーソフトウェアです。コピー条件については、ソースを参照してください。保証はありません。商品性や特定の目的への適合性についてもそうではありません。

だから私の質問は:なぜ%dとは%c異なる動作'\n'をするのscanfですか?

4

4 に答える 4

12

それは一貫した行動です。あなたはそれについて間違って考えているだけです。;)

scanf("%c", some_char); // reads a character from the key board.
scanf("%d", some_int);  // reads an integer from the key board.

だから私がこれを行うと:

printf("Insert a character: ");
scanf("%c", &ch);                // if I enter 'f'. Really I entered 'f' + '\n'
                                 // scanf read the first char and left the '\n'
printf("Insert a number: ");
scanf("%d", &actualNum);      // Now scan if is looking for an int, it sees the '\n'
                              // still, but that's not an int so it waits for the 
                              // the next input from stdin

この場合、改行を単独で消費しているわけではありません。代わりにこれを試してください:

char ch;
char ch2;
printf("Insert a character: ");
scanf("%c", &ch);
printf("Insert another character: ");
scanf("%c", &ch2); 

その時点scanf()で読み取るため、秒を「スキップ」します。一貫性があり、正しく使用する場合はそれを消費する必要があります。'\n'scanf()'\n'

于 2012-11-07T18:13:04.543 に答える
10

馬の口から:

7.21.6.2 fscanf 関数

...
5 空白文字で構成されたディレクティブは、最初の非空白文字 (未読のまま) まで入力を読み取るか、文字が読み取れなくなるまで実行されます。ディレクティブは決して失敗しません。
...
7 変換仕様であるディレクティブは、各指定子について以下で説明するように、一致する入力シーケンスのセットを定義します。変換指定は、次の手順で実行されます。

8 入力空白文字 (関数によって指定される) は、指定に 、、または指定子が含まれていない限り、isspaceスキップされます。 284) 9 入力項目は、指定に指定子が含まれていない限り、ストリームから読み取られます。[cn

n入力項目は、指定されたフィールド幅を超えず、一致する入力シーケンスであるか、そのプレフィックスである入力文字の最長シーケンスとして定義されます。 285) 入力項目の後の最初の文字があれば、それは未読のままです。入力項目の長さがゼロの場合、ディレクティブの実行は失敗します。この状態は、ファイルの終わり、エンコード エラー、または読み取りエラーによってストリームからの入力が妨げられない限り、一致の失敗です。この場合は、入力の失敗です。
284) これらの空白文字は、指定されたフィールド幅に対してカウントされません。
285) fscanf は、最大で 1 つの入力文字を入力ストリームにプッシュバックします。そのため、strtod、strtol などで受け入れられる一部のシーケンスは、fscanf では受け入れられません。

強調は私が追加しました。

%d空白は有効な整数文字列の一部ではないため、変換指定子が先頭の空白をスキップすることは理にかなっています。%cただし、空白はそれ自体で有効な場合があるため、変換指定子がそれをスキップ しないことは理にかなっています。

上記の 5 節に従って、ディレクティブの前にフォーマット文字列に空白を入れると、%c先頭の空白はすべてスキップされます。

scanf(" %c", &ch);
于 2012-11-07T19:02:27.153 に答える
2

これは、空白が整数になることはありませんが、空白は文字で構成されているためです。特にキャラクターが必要な場合は、次のようなものを試してください

scanf("%c", &ch );
while(isspace(c))
    scanf("%c" , &ch);

または!isalnum()、文字と数字のみ、または文字のみを許可する場合に使用します!isalpha()

于 2012-11-07T18:51:42.487 に答える
-2

私は専門家ではありませんが、次のことを行っていることがわかりました。

fflush(stdin);

すべてのscanfが役立つ後..

そのような:

scanf("%c", &ch);
fflush(stdin);
于 2012-11-07T18:27:22.887 に答える