I have this application where it reads user input with fgets. It works fine and have no problem if I take user input while program is running. But if I feed a file say "./myprog < in.txt", it goes into infinite loop and print my custom error message that I show when user doesn't provide valid input all over the screen. It's like return key is pressed. How do I solve that problem?
This is one section of my program that's has fgets
while(1){
mainMenu(&choice);
switch(choice)
{
case 0:
return 0;
case 1: //Add movies
getMovieData(&list);
break;
case 2:
....some initialization...
printf("Provide a name to delete : ");
fgets(inputBuffer,sizeof(inputBuffer),stdin);
trimWhiteSpace(inputBuffer);
deleteMovie(&list,inputBuffer);
break;
case 3: //List all movies
printMovieData(list);
break;
case 4: //List movies by genre
inputBuffer[0] = '\0';
printf(".....");
fgets(inputBuffer,sizeof(inputBuffer),stdin);
trimWhiteSpace(inputBuffer);
if(!isNum(inputBuffer,&genreChoice)){
showMessage("Number Expected\n");
break;
}
else if(!checkNumberValidity(&genreChoice,1,6)){
showMessage("Choose from 1 to 7\n");
break;
}
else printMoviesByGenre(list,getGenre(genreChoice-1));
break;
}
}
while(1){
printf("Provide the number of movies you would like to enter: ");
fgets(temp, sizeof(temp), stdin);
trimWhiteSpace(temp);
if(!isNum(temp,&numMovie)) printf("Enter a numeric value\n");
else if(!checkNumberValidity(&numMovie,1,MAX_MOVIES)) printf("No greater than %d\n",MAX_MOVIES);
else break;
}
Check the return value of fgets. It returns NULL on failure. At the end of the stream, fgets return NULL and feof(file) will be != 0, indicating you reached the end of stream (EOF, end of file).
As Charlie Burns said, you must exit on end of input, so do something like this:
if (fgets(temp, sizeof(temp), stdin) == NULL)
exit(EXIT_SUCCESS);
... in your while(1) loop.
Related: fgets and dealing with CTRL+D input
i don't think the infinite loop comes from fgets. But its not well declared fgets(inputBuffer,sizeof(inputBuffer),stdin); second argument must be a size, size that says how much char you wanna read. Show us where is you printf that you see during the infinite loop.
Related
I am trying to create a program, in which at the beginning it shows a menu to the user, which consists in a do{ ... }while; which reads an int., with a switch inside.
It works perfectly to read and check the integer, the problem is when writing a character or string, which gets stuck in an infinite loop showing the default message of the switch loop. The code is as follows:
int op;
printf("Choose an option:\n 1. option 1\n 2. option 2\n 3. option 3\n");
do{
scanf("%d", &op);
switch(op){
case 1: (instruction); break;
case 2: (instruction); break;
case 3: (instruction); break;
default: printf("\nPlease enter a valid option\n");
}
}while(op<1 || op>3);
It works perfectly to read and check the integer, the problem is when writing a character or string, which gets stuck in an infinite loop showing the default message of the switch loop.
scanf("%d", &op); does nothing when the input is not a valid int, you need to check the return value is 1 and if not to decide what to do like for instance read a string or flush up to the end of line, also managing the EOF case
Note in case scanf does nothing op is not set
So can be :
int op;
printf("Choose an option:\n 1. option 1\n 2. option 2\n 3. option 3\n");
do{
if (scanf("%d", &op) != 1) {
// flush all the line
while ((op = getchar()) != '\n') {
if (c == EOF) {
puts("EOF, abort");
exit(0); /* what you want */
}
}
op = -1; /* invalid value */
}
switch(op){
case 1: (instruction); break;
case 2: (instruction); break;
case 3: (instruction); break;
default: puts("\nPlease enter a valid option");
}
}
}while(op<1 || op>3);
I encourage you to never trust on an input and always check return value of scanfetc
The %d conversion specifier is seeking for decimal input only. It does not work to consume characters or strings. If you input a character instead of an decimal value, the directive will fail, and because op isn´t initialized you have undefined behavior.
To catch a string with scanf() use the %s conversion specifier or use fgets(). For only catching one character use the %c conversion specifier with scanf().
int DisplaySchedule()
{
int nDisplaySchedule_Choice;
system("cls");
printf("----- DISPLAY SCHEDULE -----\n");
printf("Pick departure station\n\t");
printf("[1] San Pedro\n\t");
printf("[2] Santa Rosa\n\t");
printf("[3] Calamba\n\n\t");
printf("[9] Go Back\n\t");
printf("[0] Exit\n\n");
printf("Choice: ");
scanf("%d", &nDisplaySchedule_Choice);
printf("\n");
switch (nDisplaySchedule_Choice) {
case 1: SanPedro(); break;
case 2: SantaRosa(); break;
case 3: Calamba(); break;
case 9: OpeningScreen(); break;
case 0: printf("Summary()"); break;
default:
printf("ERROR. INPUT A VALID RESPONSE.\n\n");
DisplaySchedule();
break;
}
return;
}
I have this code in which when I enter a letter, instead of printing the error message, it prints case 0: instead. Is there any way for me to make it so that case 0: will only function if and only if I enter "0" in the scanf statement?
You have undefined behaviour here.
scanf, when scanning for int (%d), fails because you input a character - due to matching failure. Thus not reading anything into nDisplaySchedule_Choice at all.
Since nDisplaySchedule_Choice is uninitialized to start with, it just happens to have 0 and thus goes to case 0.
The solution is to check the scanf return value before proceeding to use nDisplaySchedule_Choice. scanf returns the number of items successfully scanned.
If scanf fails to read a value (for instance because you told it to read an int and gave it a letter) it won't change your variable. So nDisplaySchedule_Choice won't change in a way that you can check in your switch. At least not if you don't initialize it - you can however set it to a value that is not covered by your switch, and if it didn't change, you know that scanf failed to read a value.
Or you could check the return value of scanf to see if it managed to read a value:
int result = scanf("%d", &nDisplaySchedule_Choice);
if (result == 0) {
int c;
while ((c = getchar()) != '\n' && c != EOF); // flush the invalid input
printf("ERROR. INPUT A VALID RESPONSE.\n\n");
DisplaySchedule();
}
else switch ...
Hi please take a look on this code:
while (cont == 1) {
...
scanf_s("%d", &input);
if (0 < input <= 5){
switch (input) {
case 1:
printf("1");
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
case 4:
printf("4");
break;
case 5:
cont = 0;
break;
default:
printf("Wrong input !");
break;
}
}else{
printf("Error, Not a number !");
}
}
If I input something that is not a number, it results in an infinite loop. How do I restrict char inputs?
You can use this:
if(scanf_s("%d", &input) != 1) {
printf("Wrong input !");
break;
}
You should ALWAYS check the return value of scanf_s anyway.
After the scanf_s() fails, you need to read at least one character (the character that it failed on); usually, it makes most sense to discard the rest of the line that the user entered:
while (cont == 1) {
int rc;
...
if ((rc = scanf_s("%d", &input)) < 0)
{
printf("EOF detected\n");
break;
}
if (rc == 0)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
printf("Error, Not a number!\n");
continue;
}
if (0 < input <= 5){
switch (input) {
case 1:
case 2:
case 3:
case 4:
printf("%d", input);
break;
case 5:
cont = 0;
break;
default:
printf("Wrong input (1-5 required)!\n");
break;
}
}
}
If EOF is detected in the 'gobble' loop, you could detect EOF there and repeat the print and break the loop immediately. OTOH, the next scanf_s() should also report EOF, so it isn't 100% necessary. It depends a little on where the prompting occurs; if you get EOF, you probably shouldn't prompt again, so maybe the test after the inner while loop should be:
if (c == EOF)
{
printf("EOF detected\n");
break;
}
else
{
printf("Error, not a number\n");
continue;
}
You can play with variants of the 'gobble' loop that read up to a newline or a digit, and use ungetch(c, stdin); to return the digit to the input stream for the next call to scanf_s() to process — you probably wouldn't prompt for more input if you're going to process the already entered digit (that would confuse).
There are endless other games you can play. One option to consider is limiting the number of failed inputs before you give up — if the user hasn't entered a valid number in 10 tries, they probably aren't going to.
Note how the error processing tells the user what the valid range of numbers is; that helps them get it right. Also notice that the messages have a newline at the end; that's generally a good idea. In contexts outside interactive I/O, the newline can help ensure that the output appears when it is printed, not some arbitrary time later when some other print adds a newline, or the output buffer fills up and the pending data is flushed after all.
Here, user is asked to press respective key to perform particular function, but suppose I pressed any character value such as "g", it goes into an infinite loop.
How to solve this issue?
int item,choice;
clrscr();
while(1)
{
printf("QUEUE SIMULAtOR");
printf("\n1:Insert");
printf("\n2:Delete");
printf("\n3:Display");
printf("\nEnter your choice: ");
scanf("%d",&choice);
switch(choice)
{
case 1:qinsert();
break;
case 2:item=qdelete();
if(item!=-1)
printf("Deleted item is %d",item);
break;
case 3:printf("\nElements in the queue are:");
qdisplay();
break;
case 4:exit(0);
default:printf("\nWrong choice try again:");
}
}
Add this after the scanf()
char ch;
while( ( ch = getchar() ) != '\n' && ch != EOF );
This should do the trick.
The problem was caused as scanf() does not store characters ( since you are using %d ) and thus they remain in the input buffer. The next scanf() tries to read this and again, instead of storing it, ignores it and it remains in the buffer. This process repeats, which causes the infinite loop.
The code I gave reads all the characters in the buffer, thus reomoving the infinite loop.
Cheers... Hope this helps you :)
This is a really awesome question.You must try to use a break statement inside a if().
Example:
void main()
{
int n;
printf("Enter the number 5\n");
while(1)
{
scanf("%d",n);
if(n==5)
{ break;
}
else
{
printf(" enter the correct num again \n");
}
}
printf(" you've entered the right number\n");
}
There you go this program will run until u enter the number 5
If you want any integer
you could use isdigit() function which is under the header file ctype
In the following piece of code what is while loop doing (marked with "loop")?:-
int main(void)
{
char code;
for (;;)
{
printf("Enter operation code: ");
scanf(" %c", &code);
while (getchar() != '\n') // loop
;
switch (code)
{
case 'i':
insert();
break;
case 's':
search();
break;
case 'u':
update();
break;
case 'p':
print();
break;
case 'q':
return 0;
default:
printf("Illegal code\n");
}
printf("\n");
}
}
Diclaimer:The code is not complete, it's just a part of the code because of which it won't compile.
getchar() used here to eat up the extra characters entered by user and the newline character \n.
Suppose a user entered the operation code as
isupq\n // '\n' is for "Enter" button
then, scanf() would read only character i and rest of the five characters would become consumed by the statement
while (getchar() != '\n')
;
Thus for next iteration scanf() will wait for user to input a character instead of reading it from the input buffer.
while (getchar() != '\n') // loop
;
is here to clean the buffer.
The problem that this while solves is that scanf(" %c", &code); only grabs a single character from the input buffer. This would be fine, except that there's still a newline left in the input buffer that resulted from hitting 'enter' after your input. a buffer clear is needed for the input buffer. that's what the while loop does
it is a common problem with c
Here application waits for the user to press enter.
Since the for loop in the given code is a infinite looping so the while loop is checking whether the input character is \n or not. In case the the character entered is \n it then moves toward the switch case. In general sense it is waiting of return key to be pressed to confirm your input.
if you use the fgetc function you don't have to worry and check for the enter key in your infinite loop. Even if you enter more than one character it will only take the first one
int main(void)
{
char code;
for (;;)
{
printf("Enter operation code: ");
code = fgetc(stdin);
switch (code)
{
case 'i':
insert();
break;
case 's':
search();
break;
case 'u':
update();
break;
case 'p':
print();
break;
case 'q':
return 0;
default:
printf("Illegal code\n");
}
printf("\n");
}
}
scanf() usually is not a good way to scan char variables, because the Enter you press after entering the character remains in input buffer. Next time you call scanf("%c", &input) this Enter already present in buffer gets read & assigned to input, thus skipping next input from user.