0

I'm having a problem understanding how to get my while loop to simply output a message saying "Invalid Input" and asking for a new question from the user unless he chooses number 1 or 2 in the list. What happens if you for example input : asdas instead of a integer the program never stops looping.

What I would like to happen is for the program to tell the user to enter a new number from 1-2 instead of simply stopping running which i can achieve by setting the default in the switch to exit(0); or runSystem = false;

For example:

CMD Says enter 1-2 the user enters : asdaf (never stops looping) as in current situation.

What I want is: asdf and then it says "enter a new choice" and waits for a correct answer.

What bothers me is the fact that the program will do as i want it to if you enter an invalid number for example: 12312312 and ask for a new entry but it doesn't work with string input.

Code:

#include <stdio.h>
#include <stdbool.h>

int main(int argc, char **argv) {

    int userinput;
    int runSystem = true;

    void options() {
        printf("<========Welcome to the program, please make a choice========> \n\n");

        printf("1: Say Hello\n");
        printf("2: Say GoodBye\n");
        printf("Please enter a choice:");
        scanf("%d", &userinput);
    }

    while (runSystem) { 
        options();  
        switch(userinput) {         
           case 1: printf("Hello!\n");
           break;           
           case 2: printf("GoodBye!\n");
           break;       
           case 3: printf("Invalid, try again\n");
           break;       
           default: 
           break;       
        }
    }
    return 0;
}
sg7
  • 6,108
  • 2
  • 32
  • 40
  • 1
    You've defined `options` as a nested function inside of `main`. This is not valid C, and is onot supported as a GCC extension. – Jonathon Reinhart Mar 10 '18 at 13:39
  • @jonathon-reinhart The question is not an exact duplicate of question 3744776: That question is about consuming whitespace in input. Here the OP inputs what he calls a String (he means a non-numerical string), and that is not consumed either by %d. So the solution could be to read a line of text with `fgets(…)` and then try parsing the line for an integer. – Renardo Mar 10 '18 at 13:52
  • Good catch Renardo. – Jonathon Reinhart Mar 10 '18 at 14:05
  • Step 1: Check the return value of `scanf("%d", &userinput);` – chux - Reinstate Monica Mar 10 '18 at 14:41

2 Answers2

1

Valid C compiler does not allow declaration of the function options inside the main.

Make that function returning your input and pass the returning value to the switch. Also in order to stop the while loop case 2: should change the runSystem to false;

input : asdas instead of a integer the program never stops looping.

This is because when scanf("%d", &userinput); failed it did not updated the variable userinput.

Check the standard 7.21.6.4 The scanf function.

You can read about behaviour of scanf here.

On success, the scanf returns the number of items successfully read. This count can match the expected number of readings or fewer, even zero, if a matching failure happens. In the case of an input failure before any data could be successfully read, EOF is returned.

Knowing that you can check the return value of scanf and make appropriate decision. Presented solution eats the bad characters.

#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>

int options(void) {

    int c;   
    int ret;
    int x = 0;
    int error = 0;
    printf("<========Welcome to the program, please make a choice========> \n\n");

    printf("1: Say Hello\n");
    printf("2: Say GoodBye\n");

    printf("Please enter a choice:");

    while(1)
    {
        c = '0';

        if(!error)
            printf("Input a number:\n");
        else
           error = 0;

        ret = scanf("%d", &x);

        if(ret == EOF) {
            return 2; // END OF PROGRAM
        }
        else
        {
            if (ret == 1){
                return x;
            }
            else  // NOT a number
            {
                printf("No letters! Input a number:\n");
                do
                {
                    c = getchar();
                    if(c == EOF)
                       return 2; // END OF PROGRAM
                }
                while (!isdigit(c) && c!='\n');

                ungetc(c, stdin);
                error = 1;
            }
        }
    }
}

int main(void) {

   int userinput;
   int runSystem = true;

   while (runSystem) {

        userinput = options();
        switch(userinput) {

            case 1: printf("Hello!\n");
            break;

            case 2: printf("GoodBye!\n");
                runSystem = false;
            break;

            default: 
            case 3: printf("Invalid, try again\n");
            break;
        }
    }
    return 0;
}

Output:

<========Welcome to the program, please make a choice========>                                                                                

1: Say Hello                                                                                                                                  
2: Say GoodBye                                                                                                                                
Please enter a choice:Input a number:                                                                                                         
X                                                                                                                                             
No letters! Input a number:                                                                                                                   
a                                                                                                                                             
No letters! Input a number:                                                                                                                   
1                                                                                                                                             
Hello!                                                                                                                                        
<========Welcome to the program, please make a choice========>                                                                                

1: Say Hello                                                                                                                                  
2: Say GoodBye                                                                                                                                
Please enter a choice:Input a number:                                                                                                         
7                                                                                                                                             
Invalid, try again                                                                                                                            
<========Welcome to the program, please make a choice========>                                                                                

1: Say Hello                                                                                                                                  
2: Say GoodBye                                                                                                                                
Please enter a choice:Input a number:                                                                                                         
2                                                                                                                                             
GoodBye!               
sg7
  • 6,108
  • 2
  • 32
  • 40
  • Still need to check return value from `scanf))` and handle errors. – Jonathan Leffler Mar 10 '18 at 14:50
  • @JonathanLeffler Thank you for your comment! You are absolutely right! I am working on it... – sg7 Mar 10 '18 at 14:52
  • Sorry to be the curmudgeon but your input does not seem to handle EOF. – Jonathan Leffler Mar 10 '18 at 16:21
  • @JonathanLeffler I really appreciate your comments! They help me as well as OP to handle the problem in the proper way. You can be as hard on me as you can, I am here to learn from the Masters. Thank you again for taking your time and correcting me. (I have updated the program.) – sg7 Mar 10 '18 at 16:54
  • Even now, when I run your program, if I type control-D (I'm on Unix; that indicates EOF — on Windows, use control-Z), I get a screen full of lines saying `No letters! Input a number:`. You have to test the `scanf()` result carefully. When there's one conversion specification as here (one `%d`), it can return -1 (EOF), 0 (didn't find a number) or 1 (found a number). On EOF, you need to stop trying to get more input. (On the nit-picking end of things: if the program doesn't use the command line options, use `int main(void)`. My default compilation options complain about unused variables.) – Jonathan Leffler Mar 10 '18 at 17:01
  • @JonathanLeffler Thank you for your patience. I am on Windows running `https://www.onlinegdb.com/online_c_compiler`. It takes `control-D` . Program would recognize it and quit via `2` case now. Thanks again! – sg7 Mar 10 '18 at 17:36
1

scanf("%d", &userinput); expects an int as the input. When you give a non-integer, scanf() won't assign it to userinput.

Check the return value of scanf() to see if it was successful. It returns the number of successful assignments it did.

When you give a string as input, scanf() won't accept it and will leave it in the input buffer unconsumed.

When you do scanf() again, the invalid input is still present in the input buffer and that is what the second scanf() tries to read. The same thing happens and this goes on. This is the reason behind your infinite loop.

To overcome this, you should consume the invalid input from the input buffer after displaying the message in case 3. Do something like

int ch;
while( (ch=getchar())!='\n' && ch!=EOF );

This will consume from the input buffer till a \n is encountered. getchar() return EOF on failure.

Edit: Standard C doesn't allow nested function definitions. The reason why you didn't get an error for that is probably because your compiler allows this as an extension. But it may not work for other compilers.

See this and this.

You could place the definition of options() within the while loop calling it or get the value for userinput as a return value or via a pointer to the variable passed to the function.

J...S
  • 5,079
  • 1
  • 20
  • 35