Как сканировать только целое число?
Я хочу, чтобы код выполнялся до тех пор, пока пользователь не введет целочисленное значение.
Код работает для массивов char и char.
Я сделал следующее:
#include<stdio.h>
int main()
{
int n;
printf("Please enter an integer: ");
while(scanf("%d",&n) != 1)
{
printf("Please enter an integer: ");
while(getchar() != '\n');
}
printf("You entered: %d\n",n);
return 0;
}
Проблема в том, что пользователь вводит значение float scanf
, которое примет его.
Please enter an integer: abcd
Please enter an integer: a
Please enter an integer: 5.9
You entered: 5
Как этого можно избежать?
Ответы
Ответ 1
- Вы берете
scanf()
.
- Вы бросаете его в корзину.
- Вы используете
fgets()
для получения всей строки.
- Вы используете
strtol()
для анализа строки как целого числа, проверяя, потребляла ли она всю строку.
char *end;
char buf[LINE_MAX];
do {
if (!fgets(buf, sizeof buf, stdin))
break;
// remove \n
buf[strlen(buf) - 1] = 0;
int n = strtol(buf, &end, 10);
} while (end != buf + strlen(buf));
Ответ 2
Используйте fgets
и strtol
,
Указатель на первый символ, следующий за целочисленным представлением в s
, сохраняется в объекте, указанном p
, если *p
отличается от \n
, то у вас неверный ввод.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *p, s[100];
long n;
while (fgets(s, sizeof(s), stdin)) {
n = strtol(s, &p, 10);
if (p == s || *p != '\n') {
printf("Please enter an integer: ");
} else break;
}
printf("You entered: %ld\n", n);
return 0;
}
Ответ 3
Попробуйте использовать следующий шаблон в scanf
. Он будет читать до конца строки:
scanf("%d\n", &n)
Вам не понадобится getchar()
внутри цикла, поскольку scanf
прочитает всю строку. Число с плавающей точкой не будет соответствовать шаблону scanf
, и приглашение снова запросит целое число.
Ответ 4
Я знаю, как это можно сделать с помощью fgets
и strtol
, я хотел бы знать, как это можно сделать, используя scanf()
(если возможно).
Как говорят другие, scanf
для этого не подходит, fgets
и strtol
является альтернативой (хотя fgets
имеет недостаток, что трудно обнаружить 0-байтовый вход и невозможно сказать, что было введено после 0-байтного, если оно есть).
Для полноты (и если допустимый ввод - целое число, за которым следует новая строка):
while(scanf("%d%1[\n]", &n, (char [2]){ 0 }) < 2)
В качестве альтернативы используйте %n
до и после %*1[\n]
с подавлением присваивания. Обратите внимание, однако (из Страница руководства Debian):
Это не преобразование, хотя оно может быть подавлено с символом подавления присваивания *
. В стандарте C говорится: "Выполнение директивы %n
не увеличивает счетчик присваивания, возвращенный при завершении выполнения", но Исправление, похоже, противоречит этому. Вероятно, разумно не делать никаких предположений о влиянии преобразований %n
на возвращаемое значение.
Ответ 5
Если вы используете scanf
, вы можете сделать что-то вроде следующего:
int val;
char follow;
int read = scanf( "%d%c", &val, &follow );
if ( read == 2 )
{
if ( isspace( follow ) )
{
// input is an integer followed by whitespace, accept
}
else
{
// input is an integer followed by non-whitespace, reject
}
}
else if ( read == 1 )
{
// input is an integer followed by EOF, accept
}
else
{
// input is not an integer, reject
}
Ответ 6
Использование fgets()
лучше.
Чтобы разрешить только использование scanf()
для ввода, сканируйте int
и следующие char
.
int ReadUntilEOL(void) {
char ch;
int count;
while ((count = scanf("%c", &ch)) == 1 && ch != '\n')
; // Consume char until \n or EOF or IO error
return count;
}
#include<stdio.h>
int main(void) {
int n;
for (;;) {
printf("Please enter an integer: ");
char NextChar = '\n';
int count = scanf("%d%c", &n, &NextChar);
if (count >= 1 && NextChar == '\n')
break;
if (ReadUntilEOL() == EOF)
return 1; // No valid input ever found
}
printf("You entered: %d\n", n);
return 0;
}
Этот подход не запрашивает повторно, если пользователь вводит только пробел, например, только Enter.
Ответ 7
Возможное решение - подумать об этом назад: принять float как входной сигнал и отклонить вход, если float не является целым числом:
int n;
float f;
printf("Please enter an integer: ");
while(scanf("%f",&f)!=1 || (int)f != f)
{
...
}
n = f;
Хотя это позволяет пользователю вводить что-то вроде 12.0 или 12e0 и т.д.