Home > OS >  Why is the scanf() skipped?
Why is the scanf() skipped?

Time:02-28

#include <stdio.h>

int main() {
    char opt;
    scanf(" %c", &opt);
    switch (opt) {
      case 'A':
        printf("Please Enter a New Name:");
        char name[200];
        scanf("%[^\n]s", name);

        printf("Please Enter a New Code:");
        char code[200];
        scanf("%s", code);

        printf("Please Enter the Number:");
        int number;
        scanf("%d", number);

        printf("%s\n%s\n%d", name, code, number);
        printf("\nPlease press Enter to confirm Creation");
    }
}

Why is the scanf of the name skipped? the output looks like

A
Please Enter a New Name:Please Enter a New Code:

Also when switch() is removed, it works normally. Is the problem on the switch()? It does not have other cases because it is an unfinished code.

CodePudding user response:

As commented by melonduofromage, your first scanf leaves the newline (\n) typed by the user after the A in the input stream. Next scanf("%[^\n]s", name) fails because the first byte from the input stream is a newline, so scanf returns immediately with a return value of 0, which you should not ignore. The program then prompts for the code and scanf skips initial white space, including the pending newline and waits for user input.

To fix this problem, add a space before the conversion specifier to skip initial white space. You should also limit the number of characters stored into the destination array: specify this number between the % and the [. Note also that the trailing s in "%[^\n]s" is useless: it is not part of the conversion specifier and scanf() will try and match it against the input stream. The correct format is scanf(" 9[^\n]", name) and the return value must be 1 for a successful conversion.

Also note that there is a missing & in scanf("%d", number): you must pass the address of the destination variable: scanf("%d", &number);

Here is a modified version:

#include <stdio.h>

int invalid_input(void) {
    fprintf(stderr, "invalid or missing input\n");
    return 1;
} 

int main() {
    char opt;
    if (scanf(" %c", &opt) != 1)
        return invalid_input();

    switch (opt) {
      case 'A':
        printf("Please Enter a New Name:");
        char name[200];
        if (scanf(" 9[^\n]", name) != 1)
            return invalid_input();

        printf("Please Enter a New Code:");
        char code[200];
        if (scanf("9s", code) != 1)
            return invalid_input();

        printf("Please Enter the Number:");
        int number;
        if (scanf("%d", &number) != 1)
            return invalid_input();

        printf("%s\n%s\n%d", name, code, number);
        printf("\nPlease press Enter to confirm Creation");
        //...
    }
    return 0;
}

CodePudding user response:

When you prompt user with the first scanf here

char opt;
scanf(" %c", &opt);

When the user enters a character, say A, "A\n" is placed in the buffer, \n coming from the user hitting the return key. The scanf takes one character as requested with the " %c" format string, and leaves the \n on the buffer.

When the second scanf is executed as

printf("Please Enter a New Name:");
char name[200];
scanf("%[^\n]s", name);

the format string "%[^\n]s" requests it to read until a \n is encountered, mind you, your buffer already contains a \n as the first character, hence scanf returns without reading anything, still leaving the \n in the buffer.

When the third scanf is executed as:

printf("Please Enter a New Code:");
char code[200];
scanf("%s", code);

(Corrected after the comments of chqrlie)

The format string "%s" ignores the leading whitespaces, hence now the \n is ignored, and scanf happily waits for your input.

Notice the leading space in the format string " %c", the space is there to get scanf ignore the leading whitespace, you can implement the same logic with your second scanf. You can either ensure that all consecutive scanf ignore the \n left in the buffer, which turns out most format specifiers do, or you can ensure that no scanf leaves it to begin with with using something like "<...>%*c" to get rid of it. Though none of which are reliable and consistent methods, and as said countless times, scanf is not designed to perform such tasks like taking user input, and you should seek alternative methods.

Also, the s in "%[^\n]s" certainly doesn't do what you expect. man page of the scanf states that

An ordinary character (i.e., one other than white space or '%'). This character must exactly match the next character of input.

If it matches, scanf discards it and continues parsing according to the remaining format specifiers. If it doesn't, scanf stops there and returns. Since it is at the end of your format string, it returns either way, hiding a potential bug from you.

  • Related