Почему scanf появляется, чтобы пропустить ввод?
===============================================

Я запутался в поведении scanf в следующей программе. scanf вводится один раз, а затем не вводится снова, пока не будет напечатан поток символов.

Ниже в программе на Си

здесь, пока я не введу любую целочисленную программу, она работает отлично, но когда вводится символ, он продолжает печатать последнее введенное значение i и никогда не останавливается (до тех пор, пока j не достигнет 10, когда цикл завершается) для scanf для следующего ввода.

то же самое происходит и в с ++.

единственное изменение в c ++ состоит в том, что вместо последнего значения печатается 0.

Я знаю, что целочисленные значения ожидаются программой, но я хочу знать, что происходит, когда символ вводится вместо целого числа?
в чем причина всего происходящего выше?

`a`, затем`cin >> i` не может прочитать его, потому что тип`i` является`int` к которому персонаж не может быть прочитан. Это означает,`a` остается в потоке навсегда.

Теперь почему`i` печать`0` это другая история. На самом деле он может напечатать что угодно. Содержание`i` не определяется, если попытка чтения не удалась. Похожая вещь случается с`scanf` также.

Правильный способ написать это так:

Или просто это (если вы хотите выйти из цикла при возникновении ошибки):



`scanf` видит символ во входном потоке, который не соответствует спецификатору преобразования, он останавливает преобразование и оставляет нарушающий символ во входном потоке.

Есть несколько способов справиться с этим. Один состоит в том, чтобы прочитать все как текст (используя`scanf` с`%s` или же`%[` спецификатор конверсии или`fgets`), а затем использовать`atoi` или же`strtol` сделать преобразование (мой предпочтительный метод).

Кроме того, вы можете проверить возвращаемое значение`scanf`; это будет указывать количество успешных конверсий. Так что если`scanf("%d", &i);` равно 0, то вы знаете, что во входном потоке плохой символ. Вы можете потреблять это с`getchar()` и попробуй еще раз.



 что говорится в руководстве[`scanf(3)`](https://www.kernel.org/doc/man-pages/online/pages/man3/scanf.3.html):

`RETURN VALUE`  

`These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.`
Не удается найти целое число.



`scanf`, вам нужно проверить его возвращаемое значение, чтобы увидеть, работает ли преобразование на входе.`scanf` вернет количество успешно отсканированных элементов. Если преобразование не сработало, оно оставит входные данные одними, и вы можете попробовать сканировать его по-другому или просто сообщить об ошибке. Например:

В вашей программе, поскольку вход остается один, ваш цикл повторяется при попытке прочитать тот же вход.

В C ++ вы проверяете на наличие ошибок, используя`fail` метод, но состояние сбоя входного потока является липким. Таким образом, он не позволит вам продолжить сканирование без очистки состояния ошибки.

В вашей программе, поскольку вы никогда не очищаете состояние ошибки, цикл повторяется с использованием`cin` в состоянии сбоя, поэтому он просто сообщает о сбое, ничего не делая.

В обоих случаях вам может быть проще или надежнее работать с вводом, если вы сначала прочитаете строку ввода, а затем попытаетесь разобрать строку ввода. В псевдокоде:

В C выгода для чтения строки состоит в том, что если она длиннее вашего буфера, вам нужно будет проверить это и объединить несколько`fgets` вызовите результаты вместе, чтобы сформировать линию. И, чтобы разобрать строку, вы можете использовать`sscanf`, который похож на`scanf` но работает на струнах.

В C ++ для быстрого анализа низкого уровня форматированного ввода я также предпочитаю`sscanf`, Но, если вы хотите использовать потоковый подход, вы можете преобразовать`string` буфер в`istringstream` сканировать вход.



 что при вводе ввод не относится к ожидаемому типу (указанному`%d` для сканирования, и`int` тип для`cin>>i;`входной поток не является расширенным, что приводит к тому, что обе операции пытаются извлечь данные одного и того же типа из одного и того же неверного ввода (и на этот раз тоже не удалось), поэтому вам никогда не потребуется другой ввод.

Чтобы этого не произошло, вам необходимо проверить возвращаемое значение обеих операций (см. Руководство по тому, как каждый сообщает об ошибках). Если ошибкаdoes произойдет (например, когда вы вводите символ), вам нужно будет удалить ошибку, использовать неверный ввод и повторить попытку. Я считаю, что в C ++ лучше читать целую строку, используя`std::gtline()` вместо`int` или даже`std::string` когда вы получаете информацию от пользователя в интерактивном режиме, то вы попадаете в это «бесконечное» цикл вы испытали.



`scanf` определить, правильно ли было проанализировано целое число (return должен = 1). В случае неудачи у вас есть выбор: либо уведомить пользователя об ошибке и прекратить его, либо восстановить, прочитав следующий токен с`scanf("%s" ...)` возможно с предупреждением.



 что ваши пользователи будут вводить действительные вещи. Лучшая практика заключается в[прочитать ввод в строку и попытаться преобразовать его в целое число](http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/). [Если ввод не целое число](https://rosettacode.org/wiki/Determine_if_a_string_is_numeric#C), вы можете дать сообщение об ошибке пользователю.