void main(){
int a;
scanf("%d",&a); // Need to check there is no character entered
printf("%d",a);
}
Здесь, если я передам abc, он напечатает 0
, если я передам 123abc
, он напечатает 123
, но мне нужно выдать ошибку в обоих условиях.
Вот как проверить, вводятся ли в качестве ввода только числа, и выдать сообщение об ошибке, если в качестве ввода вводится символ. Можно ли проверить сохранение int в качестве типа входных данных или мне следует использовать массив символов и проверить условие isalpha, пройдя массив.
Вам нужно проверить значение, возвращаемое scanf
. (Это всегда верно)
#include <stdio.h>
#include <ctype.h>
int
main(void)
{
int a;
char b;
if ( (2 == scanf("%d%c", &a, &b)) && isspace(b) ){
printf("%d\n", a);
} else {
fputs("Invalid input!\n", stderr);
}
}
Вы всегда должны проверять значение, возвращаемое scanf
. В вашем случае (с использованием %d
), если первый символ во входном потоке не является цифрой, scanf
вернет 0. Если ввод 123x
, scanf
прочитает 123 и вернет 1. Если ввод представляет собой строку, которая слишком долго представляться int
, поведение не определено.
Используя %4d%c
, вы можете проверить значение во входном потоке после того, как целое число будет прочитано из потока. В нашем случае мы считаем это ошибкой, если это значение не является пробелом. Это будет работать довольно хорошо для интерактивного использования, в котором вы ожидаете, что значение будет новой строкой, но это не работает, если поток заканчивается допустимым целым числом. В этом случае scanf
вернет 1, и вам нужно будет добавить больше логики, чтобы решить, произошла ли ошибка. Решение здесь такое же, как и у всех проблем, связанных с scanf
: перестаньте использовать scanf
, потому что это ужасный инструмент.
Также обратите внимание, что я использую %4d
в строке формата, а не %d
. Вы можете увеличить это число, но у вас должен быть модификатор ширины, чтобы предотвратить неопределенное поведение на входах, которые не могут быть представлены целым числом. Но чтобы узнать модификатор максимальной ширины, который вы можете использовать, вам нужно знать INT_MAX на машине, а фактический диапазон значений, которые можно прочитать, не является полным диапазоном int
. Язык только гарантирует, что INT_MAX не меньше 32767, поэтому %5d
небезопасно, так как ввод 99999
приведет к UB. Решение здесь такое же, как и решение всех проблем, связанных с scanf
: перестаньте использовать scanf
, потому что это ужасный инструмент.
Ключ к вашей проблеме: проверьте значение, возвращаемое scanf, чтобы узнать, сколько конверсий он сделал. Но пока подчеркну в третий раз: прекратите использовать scanf
, это ужасный инструмент!
@WeatherVane отличный вопрос. Я отредактировал решение, чтобы дать небольшой ответ.
В защиту scanf
, он вообще для этого не предназначен.
Код, который снова запрашивает ввод, если он неверен:
#include <stdio.h>
int main(void)
{
int number;
printf("Your input: ");
while(scanf("%d", &number)!=1 || getchar()!='\n')
{
scanf("%*[^\n]%*c");
printf("you must enter an integer: ");
}
printf("%d\n", number);
return 0;
}
Первый scanf делает запись, второй очищает буфер клавиатуры. getchar проверяет, является ли следующий символ клавишей ввода.
Поздравляю, лучший способ сделать scanf
пригодным для использования, который я когда-либо видел. +1
Все еще переходит в бесконечный цикл, когда вы закрываете stdin
. ./a.out < echo lol
.
Спецификатор формата %d сообщает scanf, что нужно прочитать десятичное целое число со знаком. Тип данных int представляет отрицательные целые числа, ноль и положительные целые числа. Любой из следующих шаблонов представляет допустимое целое число:
scanf ищет эти типы шаблонов при преобразовании ввода в указанный тип. Как показывают приведенные выше ответы, функция scanf возвращает количество элементов в списке аргументов, которые были успешно прочитаны.
#include <stdio.h>
int main(void)
{
int returnValue;
int number;
/*
scanf("%d", &number) will return a value of 1 if it successfully reads an
integer value. Otherwise it will return a value of 0 if it fails to read an
integer value.
The specifier d says to extract any number of decimal digits (0-9),
optionally preceded by a sign (+ or -).
Suppose the user enters the following input: -3 followed by the enter key press.
Think of scanf as reading one input character at a time. The first character read
is the minus sign '-'. Since the number may start with a minus, scanf reads the
next character '3'. This is a decimal digit which fits the integer pattern.
The next character is the enter key press '\n' which causes scanf to stop reading
the input. The characters '-' '3' are converted to the integer value -3 and
are stored in the variable named number.
The scanf function successfully read one integer value, so it returns a value
of 1 and stores it in the variable returnValue.
Suppose the user enters the following input: -3.0
The value of -3 is read and stored in the variable number. When scanf reads
the character '.', it stops reading information from the input stream
because this character is not a decimal digit. The value -3 is stored in
the variable number. The scanf function returns a value of 1 because it
successfully read an integer.
The characters '.' '0' '\n' still remain in the standard input (stdin) buffer,
waiting to be read from the input stream. The next time scanf is called
to read from the stream, it will try to read the '.' If the program needs
to read another number, we write code to clear the input stream of all
remaining characters so that scanf does not fail when next trying to read
numeric input.
Suppose the user enters the following input: a-1
The character 'a' is not a numeric digit. It will not be read from the
input stream. scanf will return a value of zero and will not write
write any value into the memory of the variable number.
The characters 'a' '-' '1' \n' all remain in the input stream.
scanf will skip over leading whitespace characters when trying to read an integer.
*/
returnValue = scanf("%d", &number);
printf("number: %d, returnValue: %d\n", number, returnValue);
return 0;
}
Почему ограничение
%4d
цифр?