51

私は、ループサイクルごとに1つずつ、標準入力から数値を読み取る小さなCプログラムを持っています。ユーザーが何らかの NaN を入力すると、エラーがコンソールに出力され、入力プロンプトが再び返されます。「0」が入力されると、ループが終了し、指定された正/負の値の数がコンソールに出力されます。プログラムは次のとおりです。

#include <stdio.h>

int main()
{
    int number, p = 0, n = 0;

    while (1) {
        printf("-> ");
        if (scanf("%d", &number) == 0) {
            printf("Err...\n");
            continue;
        }
        
        if (number > 0) p++;
        else if (number < 0) n++;
        else break; /* 0 given */
    }

    printf("Read %d positive and %d negative numbers\n", p, n);
    return 0;
}

私の問題は、非数値(「a」など)を入力すると、「-> Err ...」という無限ループが何度も発生することです。これは scanf() の問題だと思います。この関数をより安全なものに置き換えることができることはわかっていますが、この例は初心者向けで、printf/scanf、if-else、およびループについて知っているだけです。

質問への回答は、Cで他のすべてのループをscanf()スキップし、他whileの質問をざっと読んだことがありますが、この特定の問題に実際に回答するものはありません。

4

16 に答える 16

42

scanfフォーマット文字列に一致する入力のみを消費し、消費された文字数を返します。フォーマット文字列に一致しない文字があると、スキャンが停止し、無効な文字がバッファに残ります。他の人が言ったように、続行する前に無効な文字をバッファからフラッシュする必要があります。これはかなり汚い修正ですが、問題のある文字を出力から削除します。

char c = '0';
if (scanf("%d", &number) == 0) {
  printf("Err. . .\n");
  do {
    c = getchar();
  }
  while (!isdigit(c));
  ungetc(c, stdin);
  //consume non-numeric chars from buffer
}

編集:数値以外のすべての文字を一度に削除するようにコードを修正しました。非数値文字ごとに複数の「エラー」を出力しなくなりました。

これはscanfのかなり良い概要です。

于 2009-11-11T15:47:39.280 に答える
8

scanf()a次回のために" " を入力バッファに残します。おそらく何があっても行を読み取り、代わりにまたは類似getline()のもので解析するために使用する必要があります。strtol()

(はい、getline()POSIX ではなく GNU 固有です。だから何ですか? 質問には「gcc」と「linux」のタグが付けられています。 getline()また、すべてを手動で実行したくない場合を除き、テキスト行を読み取るための唯一の賢明なオプションです。)

于 2009-11-11T15:41:30.817 に答える
8

ループを続行する前に、バッファをフラッシュする必要があると思います。私がここから書いていることをテストすることはできませんが、そのようなものはおそらく仕事をするでしょう:

int c;
while((c = getchar()) != '\n' && c != EOF);
于 2009-11-11T15:42:54.937 に答える
4

scanf()無効な文字を持つバッファを使用して処理するのではなく、とを使用fgets()してsscanf()ください。

/* ... */
    printf("0 to quit -> ");
    fflush(stdout);
    while (fgets(buf, sizeof buf, stdin)) {
      if (sscanf(buf, "%d", &number) != 1) {
        fprintf(stderr, "Err...\n");
      } else {
        work(number);
      }
      printf("0 to quit -> ");
      fflush(stdout);
    }
/* ... */
于 2009-11-11T16:00:53.620 に答える
4

scanf他の回答で指摘された問題のため、別のアプローチの使用を検討する必要があります。私はいつもscanf、深刻な入力の読み取りと処理には限界がありすぎることに気づきました。with で行全体を読み取り、andfgetsのような関数で作業することをお勧めします (BTW は整数を正しく解析し、無効な文字がどこから始まるかを正確に教えてくれます)。strtokstrtol

于 2009-11-11T15:53:15.440 に答える
3

同様の問題がありました。scanf のみを使用して解決しました。

Input "abc123<Enter>"それがどのように機能するかを確認します。

#include <stdio.h>
int n, num_ok;
char c;
main() {
    while (1) {
        printf("Input Number: ");
        num_ok = scanf("%d", &n);
        if (num_ok != 1) {
            scanf("%c", &c);
            printf("That wasn't a number: %c\n", c);
        } else {
            printf("The number is: %d\n", n);
        }
    }
}
于 2012-09-14T13:25:22.120 に答える
1

一部のプラットフォーム (特に Windows と Linux) では、以下を使用できますfflush(stdin);

#include <stdio.h>

int main(void)
{
  int number, p = 0, n = 0;

  while (1) {
    printf("-> ");
    if (scanf("%d", &number) == 0) {
        fflush(stdin);
        printf("Err...\n");
        continue;
    }
    fflush(stdin);
    if (number > 0) p++;
    else if (number < 0) n++;
    else break; /* 0 given */
  }

  printf("Read %d positive and %d negative numbers\n", p, n);
  return 0;
}
于 2012-10-25T16:25:57.717 に答える
0

私は同じ問題を抱えていましたが、ややハックな解決策を見つけました。私fgets()は入力を読み取ってから、それを にフィードしていましたsscanf()。これは、無限ループの問題に対する悪い修正ではありません。単純な for ループを使用して、数字以外の文字を検索するように C に指示します。以下のコードは、 のような入力を許可しません123abc

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main(int argc, const char * argv[]) {

    char line[10];
    int loop, arrayLength, number, nan;
    arrayLength = sizeof(line) / sizeof(char);
    do {
        nan = 0;
        printf("Please enter a number:\n");
        fgets(line, arrayLength, stdin);
        for(loop = 0; loop < arrayLength; loop++) { // search for any none numeric charcter inisde the line array
            if(line[loop] == '\n') { // stop the search if there is a carrage return
                break;
            }
            if((line[0] == '-' || line[0] == '+') && loop == 0) { // Exculude the sign charcters infront of numbers so the program can accept both negative and positive numbers
                continue;
            }
            if(!isdigit(line[loop])) { // if there is a none numeric character then add one to nan and break the loop
                nan++;
                break;
            }
        }
    } while(nan || strlen(line) == 1); // check if there is any NaN or the user has just hit enter
    sscanf(line, "%d", &number);
    printf("You enterd number %d\n", number);
    return 0;
}
于 2013-12-30T08:38:03.703 に答える
0

これを使用してみてください:

if (scanf("%d", &number) == 0) {
        printf("Err...\n");
        break;
    }

これは私にとってはうまくいきました...これを試してください..Err ..は1回だけ実行する必要があるため、 continueステートメントは適切ではありません。だから、私がテストしたブレークを試してください...これはあなたにとってうまくいきました..私はテストしました....

于 2016-10-07T05:34:49.560 に答える
-1

こんばんは。私は最近同じ問題を経験しており、多くの人に役立つ解決策を見つけました. さて、実は関数「scanf」はメモリにバッファを残してしまう…ということで、無限ループを起こしているのです。したがって、最初の scanf に「null」値が含まれている場合は、実際にこのバッファを別の変数に「保存」する必要があります。ここに私が意味するものがあります:

#include <stdio.h>
int n;
char c[5];
main() {
    while (1) {
        printf("Input Number: ");
        if (scanf("%d", &n)==0) {  //if you type char scanf gets null value
            scanf("%s", &c);      //the abovementioned char stored in 'c'
            printf("That wasn't a number: %s\n", c);
        }
        else printf("The number is: %d\n", n);
    }
}
于 2016-12-14T21:56:50.577 に答える
-1

スキャンする前に入力バッファをフラッシュします。

while(getchar() != EOF) continue;
if (scanf("%d", &number) == 0) {
    ...

提案するつもりでしfflush(stdin)たが、どうやら未定義の動作が発生するようです。

あなたのコメントに応えて、プロンプトを表示したい場合は、出力バッファをフラッシュする必要があります。デフォルトでは、これは改行を印刷するときにのみ発生します。お気に入り:

while (1) {
    printf("-> ");
    fflush(stdout);
    while(getchar() != EOF) continue;
    if (scanf("%d", &number) == 0) {
    ...
于 2009-11-11T15:43:17.223 に答える