Почему scanf () вызывает бесконечный цикл в этом коде? - PullRequest
44 голосов
/ 11 ноября 2009

У меня есть небольшая 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 и loop.

Я уже прочитал ответы на этот вопрос и пролистал другие вопросы, но на самом деле ничего не решило эту конкретную проблему.

Ответы [ 14 ]

0 голосов
/ 07 октября 2016

попробуйте использовать это:

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

это работало нормально для меня ... попробуйте это .. оператор continue не подходит, так как Err .. должен выполняться только один раз. Итак, попробуйте перерыв , который я проверял ... это работало хорошо для вас .. я проверял ....

0 голосов
/ 16 марта 2015

Привет, я знаю, что это старая ветка, но я только что закончил школьное задание, где столкнулся с той же проблемой. Мое решение состоит в том, что я использовал get (), чтобы узнать, что оставил scanf ().

Здесь OP-код слегка переписан; Вероятно, бесполезно для него, но, возможно, это поможет кому-то еще.

#include <stdio.h>

    int main()
    {
        int number, p = 0, n = 0;
        char unwantedCharacters[40];  //created array to catch unwanted input
        unwantedCharacters[0] = 0;    //initialzed first byte of array to zero

        while (1)
        {
            printf("-> ");
            scanf("%d", &number);
            gets(unwantedCharacters);        //collect what scanf() wouldn't from the input stream
            if (unwantedCharacters[0] == 0)  //if unwantedCharacters array is empty (the user's input is valid)
            {
                if (number > 0) p++;
                else if (number < 0) n++;
                else break; /* 0 given */
            }
            else
                printf("Err...\n");
        }
        printf("Read %d positive and %d negative numbers\n", p, n);
        return 0;
    }
0 голосов
/ 30 декабря 2013

У меня была такая же проблема , и я нашел несколько хакерское решение. Я использую fgets(), чтобы прочитать ввод, а затем передать его на sscanf(). Это неплохое решение проблемы бесконечного цикла, и с помощью простого цикла я говорю 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;
}
0 голосов
/ 11 ноября 2009

Очистить входной буфер перед сканированием:

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) {
    ...
...