Reputation:
I have the below code :
#include <stdio.h>
void printMenu() {
printf("********************************\n");
printf("*Enter a number (-1 to exit): *");
printf("\n* 1 - Add new student *");
printf("\n* 2 - Delete a student *");
printf("\n* 3 - Update student *");
printf("\n* 4 - Print a student *");
printf("\n* 5 - Print all students *");
printf("\n********************************\n");
printf("\nEnter: ");
}
int main (int argc, char **argv) {
int a;
printMenu();
scanf("%d", &a);
while(a != -1) {
switch(a) {
case 1:
printf("1\n");
break;
case 2:
printf("2\n");
break;
case 3:
printf("3\n");
break;
case 4:
printf("4\n");
break;
case 5:
printf("5\n");
break;
default:
printf("\nInvalid answer!\n");
break;
}
puts("");
printMenu();
scanf("%d", &a);
}
return 0;
}
I would like to check the input of scanf
. For example if user enters a number it works successfully, but if user enter something like a string or a char it print non-stop the menu again and again.
I would like to check if user enters a number or not. If not I would like to ask again about input. I have tried things like:
if(scanf("%d", &a)!=1) {
printf("Enter again: ");
scanf("%d", &a);
}
Or:
assert(scanf("%d", &a);
With assert
function program stops executing but I want it to continue after while.
Any ideas?
Upvotes: 0
Views: 310
Reputation: 16910
When dealing with interactive input, I find convenient to always
consume the input line, then analyse it afterwards.
This way, whatever has been given on input (conforming to expectations
or not), it won't stay in the input stream blocking further analysis.
This generally looks like this
/**
gcc -std=c99 -o prog_c prog_c.c \
-pedantic -Wall -Wextra -Wconversion \
-Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
-g -O0 -UNDEBUG -fsanitize=address,undefined
**/
#include <stdio.h>
int
main(void)
{
for(;;)
{
printf("Please, provide something interesting: ");
char input_line[0x100];
if(!fgets(input_line, sizeof(input_line), stdin))
{
printf("no more input\n");
break; // leave the loop
}
int answer;
if(sscanf(input_line, "%d", &answer)!=1)
{
printf("an integer was expected.\n");
continue; // go back to the prompt
}
printf("%d + %d = %d\n", // make use of the provided information
answer, answer, answer+answer);
}
return 0;
}
Upvotes: 1
Reputation: 32596
but if user enter something like a string or a char (e.g. a or grebv) it print non-stop the menu again and again
this is because when scanf fails nothing is read, so you have to bypass the non number for instance reading up to the end of line with getchar/fgets. Warning you also have to manage the case of EOF for instance because the stdin is redirected in a file.
To do :
if(scanf("%d", &a)!=1) { printf("Enter again: "); scanf("%d", &a); }
is not enough even adding the flush of the invalid input before the second scanf because you can have two or more consecutive errors (the second scanf fails too).
A way can be for instance :
#include <stdio.h>
void printMenu() {
fputs("********************************\n"
"*Enter a number (-1 to exit): *\n"
"* 1 - Add new student *\n"
"* 2 - Delete a student *\n"
"* 3 - Update student *\n"
"* 4 - Print a student *\n"
"* 5 - Print all students *\n"
"********************************\n"
"\nEnter: ", stdout);
}
int main()
{
int a;
do {
printMenu();
if (scanf("%d", &a) != 1) {
/* flush invalid input up to the end of line */
while ((a = getchar()) != '\n') {
if (a == EOF) {
puts("...EOF...");
return -1;
}
}
a = 0; /* any 'invalid' value managed in the 'default' case of the 'switch'*/
}
switch (a) {
case -1:
break; /* or 'return 0;' and the 'do while' is a 'for(;;)' */
case 1:
printf("1\n");
break;
case 2:
printf("2\n");
break;
case 3:
printf("3\n");
break;
case 4:
printf("4\n");
break;
case 5:
printf("5\n");
break;
default:
puts("\nInvalid answer!");
break;
}
} while (a != -1);
return 0;
}
Compilation and executions:
/tmp % gcc -Wall a.c
/tmp % ./a.out
********************************
*Enter a number (-1 to exit): *
* 1 - Add new student *
* 2 - Delete a student *
* 3 - Update student *
* 4 - Print a student *
* 5 - Print all students *
********************************
Enter: 1
1
********************************
*Enter a number (-1 to exit): *
* 1 - Add new student *
* 2 - Delete a student *
* 3 - Update student *
* 4 - Print a student *
* 5 - Print all students *
********************************
Enter: aze
Invalid answer!
********************************
*Enter a number (-1 to exit): *
* 1 - Add new student *
* 2 - Delete a student *
* 3 - Update student *
* 4 - Print a student *
* 5 - Print all students *
********************************
Enter: 2
2
********************************
*Enter a number (-1 to exit): *
* 1 - Add new student *
* 2 - Delete a student *
* 3 - Update student *
* 4 - Print a student *
* 5 - Print all students *
********************************
Enter: -1
/tmp %
/tmp % ( echo 1 ; echo aze ; echo 2 ) | ./a.out
********************************
*Enter a number (-1 to exit): *
* 1 - Add new student *
* 2 - Delete a student *
* 3 - Update student *
* 4 - Print a student *
* 5 - Print all students *
********************************
Enter: 1
********************************
*Enter a number (-1 to exit): *
* 1 - Add new student *
* 2 - Delete a student *
* 3 - Update student *
* 4 - Print a student *
* 5 - Print all students *
********************************
Enter:
Invalid answer!
********************************
*Enter a number (-1 to exit): *
* 1 - Add new student *
* 2 - Delete a student *
* 3 - Update student *
* 4 - Print a student *
* 5 - Print all students *
********************************
Enter: 2
********************************
*Enter a number (-1 to exit): *
* 1 - Add new student *
* 2 - Delete a student *
* 3 - Update student *
* 4 - Print a student *
* 5 - Print all students *
********************************
Enter: ...EOF...
/tmp %
Upvotes: 0