Из стандарта языка C (n1256):
7.19.6.2 The fscanf function
...
4 The fscanf function executes each directive of the format in turn. If a directive fails, as detailed below, the function returns. Failures are described as input failures (due to the occurrence of an encoding error or the unavailability of input characters), or matching
failures (due to inappropriate input).
...
7 A directive that is a conversion specification defines a set of matching input sequences, as described below for each specifier. A conversion specification is executed in the following steps:
8 Input white-space characters (as specified by the isspace function) are skipped, unless
the specification includes a [, c, or n specifier.250)
9 An input item is read from the stream, unless the specification includes an n specifier. An input item is defined as the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence.251) The first character, if any, after the input item remains unread. If the length of the input item is zero, the execution of the directive fails; this condition is a matching failure unless end-of-file, an encoding error, or a read error prevented input from the stream, in which case it is an input failure.
10 Except in the case of a % specifier, the input item (or, in the case of a %n directive, the count of input characters) is converted to a type appropriate to the conversion specifier. If the input item is not a matching sequence, the execution of the directive fails: this condition is a matching failure. Unless assignment suppression was indicated by a *, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
Выделение добавлено в параграф 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
.
person
John Bode
schedule
25.10.2010