от C language standard (n1256):
7.19.6.2 Функция fscanf
...
4 Функция fscanf выполняет по очереди каждую директиву формата. Если директива не работает, как описано ниже, функция возвращает. Ошибки описываются как сбои ввода (из-за возникновения ошибки кодирования или недоступности входных символов) или соответствия сбоям (из-за несоответствующего ввода).
...
7 Директива, являющаяся спецификацией преобразования, определяет набор совпадающих входных последовательностей, как описано ниже для каждого спецификатора. Спецификация преобразования выполняются в следующих шагах:
8 входных белых символы пробела (как определенно с помощью функции isspace) пропускаются, если спецификация не включает в себя
[,
гр или
п спецификатора ,
250)
9 Элемент ввода читается из потока, если спецификация не включает в себя
п спецификатор. Элемент ввода определяется как самая длинная последовательность входных символов, которая не превышает заданную ширину поля и которая является или является префиксом соответствующей последовательности ввода.
251) Первый символ, если он есть, после ввода элемента остается непрочитанным. Если длина входного элемента равна нулю, выполнение директивы выходит из строя; это условие является совпадающим сбоем, если только конец файла, ошибка кодирования или ошибка чтения не позволяют вводить данные из потока, и в этом случае это ошибка ввода.
в 10 За исключением случая
% спецификатора, входной позиции (или, в случае
% п директивы в, количество вводимых символов) преобразуется к типу, соответствующего спецификатора преобразования ,
Если входной элемент не соответствует последовательности, выполнение директивы не выполняется: это условие является несоответствующим. Если исключение присваивания не было указано *, результат преобразования помещается в объект, на который указывает первый аргумент, следующий за аргументом формата, который еще не получил результат преобразования. Если этот объект не имеет соответствующего типа или если результат преобразования не может быть представлен в объекте, поведение не определено.
Акцент, добавленный в параграфе 10. Спецификатор преобразования %d
ожидает, что входной текст будет отформатирован как десятичное целое. Если это не так, преобразование завершается с ошибкой, и символ, который вызвал отказ при преобразовании, остается во входном потоке. Дальнейшие звонки на scanf()
с помощью спецификатора преобразования %d
будут дросселироваться по одному и тому же символу.
scanf()
возвращает количество успешных заданий; Вы должны проверить этот результат, чтобы увидеть, если преобразование удалось, например, так:
int x = 0;
while (x != 4)
{
int result = scanf("%d", &x);
if (result != 1)
{
printf("Last call to scanf() failed; exiting\n");
break;
}
}
К сожалению, у вас еще есть плохой вход застрял во входном потоке. Существует ряд стратегий для решения этой проблемы. Вы можете удалить нарушитель персонаж с getchar
и попробуйте еще раз:
while (x != 4)
{
int tmp;
if (scanf("%d", &tmp) == 0)
getchar();
else
x = tmp;
}
Или вы могли бы попытаться прочитать до следующей строки, при условии, что все остальные входы b0rked:
while (x != 4)
{
int tmp;
if (scanf("%d", &tmp) == 0)
while (getchar() != '\n')
;
else
x = tmp;
}
Или вы могли бы попробовать читать ввод как текста и преобразовать в целое число с помощью strtol()
(мой предпочтительный метод):
char input[SOME_SIZE];
int x = 0;
...
while (x != 4)
{
if (fgets(input, sizeof input, stdin))
{
char *check;
int tmp = (int) strtol(input, &check, 10);
if (!isspace(*check) && *check != 0)
{
printf("%s is not a valid integer: try again\n", input);
}
else
{
x = tmp;
}
}
else
{
printf("Read error on standard input\n");
break;
}
}
Это больше работы, но это позволяет вам ломать неудачный ввод до получает назначение на x
.
проголосуйте за ссылку и за решение getchar() – Aboelnour
Просто небольшое замечание. Игнорирование части ввода на самом деле является очень плохой практикой. Вы должны сообщить об ошибке при первом признаке проблемы, а не продолжить чтение. –