Как сканировать только одно целое и повторять чтение, если пользователь вводит нецифровые символы?
Вот небольшая проблема с tyro с кодом C, пытающимся просто запретить пользователю вводить символ или целое число меньше 0 или более 23.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char *input;
char *iPtr;
int count = 0;
int rows;
printf("Enter an integer: ");
scanf("%s", input);
rows = strtol(input, &iPtr, 0);
while( *iPtr != '\0') // Check if any character has been inserted
{
printf("Enter an integer between 1 and 23: ");
scanf("%s", input);
}
while(0 < rows && rows < 24) // check if the user input is within the boundaries
{
printf("Select an integer from 1 to 23: ");
scanf("%s", input);
}
while (count != rows)
{
/* Do some stuff */
}
return 0;
}
Я сделал это на полпути, и небольшое повышение будет оценено.
Ответы
Ответ 1
Используйте scanf("%d",&rows)
вместо scanf("%s",input)
Это позволяет получить прямое значение integer из stdin без необходимости преобразования в int.
Если пользователь вводит строку, содержащую нецифровые символы, вы должны очистить свой stdin до следующего scanf("%d",&rows)
.
ваш код может выглядеть так:
#include <stdio.h>
#include <stdlib.h>
int clean_stdin()
{
while (getchar()!='\n');
return 1;
}
int main(void)
{
int rows =0;
char c;
do
{
printf("\nEnter an integer from 1 to 23: ");
} while (((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin()) || rows<1 || rows>23);
return 0;
}
Объяснение
1)
scanf("%d%c", &rows, &c)
Это означает, что от пользователя вводится целое число и рядом с ним нецифровой символ.
Пример1: Если пользователь вводит aaddk
, а затем ENTER
, scanf вернет 0. Ничего не закрыто
Пример2: Если пользователь вводит 45
, а затем ENTER
, scanf вернет 2 (2 элемента закрыты). Здесь %d
является capting 45
и %c
является capting \n
Пример3: Если пользователь вводит 45aaadd
, а затем ENTER
, scanf вернет 2 (2 элемента закрыты). Здесь %d
- capting 45
, а %c
- capting a
2)
(scanf("%d%c", &rows, &c)!=2 || c!='\n')
В примере1: это условие TRUE
, потому что scanf return 0
(!=2
)
В примере2: это условие FALSE
, потому что scanf return 2
и c == '\n'
В примере3: это условие TRUE
, потому что scanf return 2
и c == 'a' (!='\n')
3)
((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin())
clean_stdin()
всегда TRUE
, потому что функция всегда возвращает 1
В примере 1: (scanf("%d%c", &rows, &c)!=2 || c!='\n')
- TRUE
, поэтому условие после &&
должно быть проверено, чтобы выполнить clean_stdin()
, и все условие TRUE
В примере2: (scanf("%d%c", &rows, &c)!=2 || c!='\n')
есть FALSE
, поэтому условие после &&
не будет проверено (поскольку его результат будет равен всего FALSE
), поэтому clean_stdin()
не будет выполняться, и все условие FALSE
В примере 3: (scanf("%d%c", &rows, &c)!=2 || c!='\n')
- TRUE
, поэтому условие после &&
должно быть проверено, чтобы выполнить clean_stdin()
и все условие TRUE
Итак, вы можете заметить, что clean_stdin()
будет выполняться только в том случае, если пользователь вводит строку, содержащую нецифровой символ.
И это условие ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin())
вернет FALSE
, только если пользователь вводит integer
и ничего больше
И если условие ((scanf("%d%c", &rows, &c)!=2 || c!='\n') && clean_stdin())
равно FALSE
и integer
находится между и 1
и 23
, тогда цикл while
будет ломаться иначе, цикл while
будет продолжен
Ответ 2
#include <stdio.h>
main()
{
char str[100];
int num;
while(1) {
printf("Enter a number: ");
scanf("%[^0-9]%d",str,&num);
printf("You entered the number %d\n",num);
}
return 0;
}
%[^0-9]
в scanf()
копирует все, что не находится между 0
и 9
. По сути, он очищает входной поток без цифр и помещает его в str
. Ну, длина нецифровой последовательности ограничена 100. Следующие %d
выбирают только целые числа во входном потоке и помещают его в num
.
Ответ 3
Вы можете создать функцию, которая читает целое число от 1 до 23 или возвращает 0, если не-int
например.
int getInt()
{
int n = 0;
char buffer[128];
fgets(buffer,sizeof(buffer),stdin);
n = atoi(buffer);
return ( n > 23 || n < 1 ) ? 0 : n;
}
Ответ 4
char check1[10], check2[10];
int foo;
do{
printf(">> ");
scanf(" %s", check1);
foo = strtol(check1, NULL, 10); // convert the string to decimal number
sprintf(check2, "%d", foo); // re-convert "foo" to string for comparison
} while (!(strcmp(check1, check2) == 0 && 0 < foo && foo < 24)); // repeat if the input is not number
Если ввод является номером, вы можете использовать foo
в качестве вашего ввода.
Ответ 5
Вам нужно будет повторить свой вызов strtol
внутри ваших петель, где вы просите пользователя повторить попытку. Фактически, если вы сделаете цикл a do { ... } while(...);
, а не время, вы не получите одинаковое повторение в два раза.
Вы также должны форматировать свой код, чтобы можно было видеть, где код находится внутри цикла, а не.
Ответ 6
MOHAMED, ваш ответ велик, и это действительно помогло мне. Здесь я разместил код, который, я думаю, немного проще:
#include <stdio.h>
int getPositive(void);
void clean_input(void);
int main(void) {
printf("%d\n",getPositive());
return 0;
}
int getPositive(void) {
int number;
char buffer; // Holds last character from user input.
// (i.e '\n' or any other character besides numbers)
int flag; // Holds scanf return value
do{
flag = scanf("%d%c", &number, &buffer); // Gets input from user
// While scanf did not read 2 objects (i.e 1 int & 1 char)
// or the user inputed a number and then a character (eg. 12te)
// ask user to type a valid value
while (flag !=2 || buffer!='\n') {
clean_input();
printf("%s","You have typed non numeric characters.\n"
"Please type an integer\n?");
flag = scanf("%d%c", &number, &buffer);
}
if(number<0) {
printf("%s","You have typed a non positive integer\n"
"Please type a positive integer\n?");
} else { // If user typed a non negative value, exit do-while.
break;
}
}while(1);
}
void clean_input(void) {
while (getchar()!='\n');
return;
}
В моем случае я хочу, чтобы номер был просто положительным. Если вы хотите, чтобы ваш номер находился между 1 и 23, вы заменяете number<0
на number<1 || number>23
в инструкции if. Также вам нужно будет изменить printf
, чтобы напечатать соответствующее сообщение.
Ответ 7
Приведенный выше сценарий, созданный Yonggoo Noh, хорошо сработал для меня.
Я изменил его, чтобы включить значение 0, чтобы вернуться к main() в любое время, но у меня есть проблема:
- Иногда, после возврата в main(), когда я снова вхожу в скрипт, он запрашивает у меня значение ("check1") 2 или более раз.
Почему это произойдет?
char check1[10], check2[10];
int foo;
do{
printf(">> ");
scanf(" %s", check1);
foo = strtol(check1, NULL, 10); // convert the string to decimal number
sprintf(check2, "%d", foo); // re-convert "foo" to string for comparison
} while (!(strcmp(check1, check2) == 0 && ((0 < foo && foo < 24) || foo==0))); // repeat if the input is not number
if (n==0){ main(); }