Scanf и петли - PullRequest
       34

Scanf и петли

2 голосов
/ 04 октября 2010

здесь фрагмент кода, который должен циклически повторяться до тех пор, пока пользователь не введет число от 0 до 15

        int input;

        do
        {

                printf("Enter a number => ");
                scanf("%d",&input);
                printf("\n %d \n",input);

        }
        while (!(input>0 && input <15));

Однако если пользователь вводит что-то вроде «gfggdf», это приводит кцикл повторяется снова и снова и снова и никогда не запрашивает у пользователя ввода снова ... консоль выглядит так

Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
(looping indefinitely)

После просмотра этой книги мне кажется, что мне нужно сделать что-то подобное, чтобы предотвратить этоне происходит.

int input, error, status;
char skip_ch;

do
{
        error = 0;

        printf("Enter a number => ");
        status = scanf("%d",&input);
        printf("\n %d \n",input);

        if(status!=1)
        {
                error=1;
        }
        else if(input < 0 || input >15){
                error = 1;
        }

        do
        {
                scanf("%c",&skip_ch);
        }while(skip_ch != '\n');
}
while (error);

Я понимаю необходимость проверки состояния scanf, чтобы убедиться, что это был допустимый ввод. Что я не понимаю во внутреннем цикле do-while.Я чувствую, что книга никогда не объясняла мне, почему scanf нужно вызывать несколько раз таким образом, как будто буфер scanf заполнен кучей мусора, и он каким-то образом очищает его, просто просматривая его миллион раз дляВы.

Может кто-нибудь объяснить мне эту черную магию?

Ответы [ 3 ]

5 голосов
/ 04 октября 2010

Вот почему так много ответов на подобные вопросы, которые рекомендуют не использовать scanf().

Кроме того, вы должны проверить возвращаемое значение из scanf(), потому что оно говорит вам, когда что-то пошло не такникакое значение не может быть преобразовано.

Нормальным рекомендуемым решением является комбинация fgets() для чтения строк ввода и sscanf() для анализа строки после ее чтения.

Второй циклв вашем примере происходит чтение символов вплоть до новой строки, включая повторную синхронизацию scanf() и пропуск любых поддельных данных.Это многословный способ сделать это;вместо этого было бы проще использовать getchar():

int c;
while ((c = getchar()) != EOF && c != '\n')
    ;

Обратите внимание на использование 'int c;' - тип принципиально не 'char' или 'unsigned char', потому что он должен хранитьвсе возможные значения char плюс EOF.

3 голосов
/ 04 октября 2010

Исходный код зацикливается бесконечно, потому что недопустимые данные ("gfggdf") не удаляются из входного буфера, когда scanf не может преобразовать его в целое число - он остается во входном буфере, поэтомуследующий вызов scanf просматривает те же данные, и (конечно) все еще не может преобразовать их в целое число, поэтому цикл выполняется еще раз, а результаты все еще не изменились.

The:

do {
        scanf("%c",&skip_ch);
}while(skip_ch != '\n');

просто читает по одному символу за раз (и игнорирует его) до тех пор, пока не достигнет конца строки.Если вы предпочитаете избавляться от мусора во входном буфере без цикла, вы можете использовать что-то вроде: scanf("%*[^\n]");

Другая широко используемая возможность (возможно, более) - начать с чтения всей строки,затем пытается конвертировать то, что в строке.Независимо от того, преобразуется он или нет, вы уже прочитали все данные до конца строки, поэтому следующая попытка чтения / преобразования начнется со следующей строки независимо от того, сработало преобразование или нет.Это имеет один потенциальный недостаток: если вы получили действительно длинную строку ввода, вы можете закончить чтение и хранение большого количества данных, которые вы не имеете реального использования.Это редко имеет большое значение, но вы все равно должны знать об этом.

1 голос
/ 04 октября 2010

Прежде всего, избегайте использования scanf(), используйте fgets().

Для оценки вашего состояния (первый код). 0 > 0 - это false. 0 < 15 - это true. false && true - это false. !false - это true. Вот почему он зацикливается бесконечно.

...