Search code examples
c++cscanf

Why does scanf_s() isn't working second time I am calling it in order to verify if user provided correct input?


I am writing an application with a menu and I am asking the user to provide an integer representing an option from the menu

1. Option 1
2. Option 2
3. Option 3
...

This option is stored in a variable called

 option

I want to avoid wrong input such as "12a", "1a2", "anyString" and I've read that this can be achieved by storing return value of scanf_s() function.

So I stored it in a variable called

ret

and now I want that every time user provides wrong input to prompt them to enter a new value.

So I wrote something like this:

int ret = scanf_s("%d", &option);
while (!ret)
{
    cout << "Provide an integer, not a string! :)\n";
    ret = scanf_s("%d", &option);
}

The problem is when it enters the while it is not allowing user to enter a new value and hence the value of ret never changes, making it run endlessly.

How can I achieve what I am looking for?


Solution

  • When scanf_s fails to convert an integer, the offending input stays in the input stream. Calling scanf_s("%d", &option) again will produce the same result until some characters are removed from the input stream. Note also that using scanf_s or scanf directly from stdin is error prone: the newline entered by the user stays in the input stream and will be read by a subsequent call to getchar() or fgets(), potentially causing unexpected behavior.

    To avoid these pitfalls, it is recommended to read one line at a time with fgets() and convert it with sscanf() this way:

    #ifdef _MSC_VER
    #define _CRT_SECURE_NO_WARNINGS
    #endif
    
    #include <stdio.h>
    
    int main() {
        char buf[80];
        int option;
        char cc;
    
        for (;;) {
            print_menu();  // output the menu options
            if (!fgets(buf, sizeof buf, stdin)) {
                /* end of file reached: break from the loop */
                break;
            }
            /* parse exactly one integer with optional leading and trailing whitespace */
            if (sscanf(buf, "%d %c", &option, &cc) != 1) {
                printf("invalid input: %s", buf);
                printf("enter one integer exactly\n");
                continue;
            }
            printf("option is %d\n", option);
            // handle option
        }
        return 0;
    }