-1

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);
Harsh
  • 350
  • 1
  • 4
  • 13
  • Use `fgets()` for user input. – pmg May 24 '20 at 13:29
  • 1
    `scanf` will not read non-numeric content, leaving any letters as unread input. On the next iteration of the loop it tries again, with the same results, leaving the input still unread. This is the reason for your infinite loop. Any part of this explanation is unclear to you? If no, then what exactly is your question? – Sam Varshavchik May 24 '20 at 13:31
  • Check return value from scanf – klutt May 24 '20 at 13:42
  • 1
    Hello Rodrigo. Why do you not simply use a char for you main ? – Franck Might May 24 '20 at 13:43

2 Answers2

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

bruno
  • 32,421
  • 7
  • 25
  • 37
  • Note by definition after `while ((op = getchar()) != '\n') {..}` *op* values '\n' and in ASCII newline is not 1, 2 or 3, but I force the value to be compatible with any character encoding – bruno May 24 '20 at 13:44
  • Thank you! Now it works and it doesnt get stuck in the loop, I just dont think it is somehow "efficient", but it is what I need so.. thanks ;) – Rodrigo Duarte May 24 '20 at 13:46
0

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().