0
#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.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 2
    Your first `scanf` leaves a `\n` on the buffer. Second one sees it and stops reading, also leaving it in the buffer, so does the third one. When it finally comes to the forth one, `%d` format string ignores it and waits for you. Don't use `scanf` to get input from user, [see](http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html). – aulven Feb 27 '22 at 10:01
  • @melonduofromage Please create an answer. – Yunnosch Feb 27 '22 at 10:02
  • I also don't believe for a minute the claim "when switch() is removed, it works normally", unless "normally" means it fails as-designed. That isn't the only change if this magically starts working. The trailing `s` on that name read assuredly wrong, and `scanf("%d", number);` is absolutely wrong. There is no way this runs well. – WhozCraig Feb 27 '22 at 10:05
  • @WhozCraig: removing both the `switch` and the `scanf(" %c", &opt);` does change the behavior. – chqrlie Feb 27 '22 at 10:09
  • And so the `scanf("%[^\n]s", name);` should be `scanf(" %199[^\n]", name);` (three changes a) space to filter newline, b) length restriction, c) remove the "beginner's `s`"). Please see [scanf() leaves the newline char in the buffer](https://stackoverflow.com/questions/5240789/scanf-leaves-the-new-line-char-in-the-buffer). – Weather Vane Feb 27 '22 at 10:09
  • @chqrlie Sure, but the OP never claimed they removed the `scanf(" %c", &opt);` – WhozCraig Feb 27 '22 at 10:10

2 Answers2

1

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(" %199[^\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(" %199[^\n]", name) != 1)
            return invalid_input();

        printf("Please Enter a New Code:");
        char code[200];
        if (scanf("%199s", 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;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

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.

aulven
  • 521
  • 3
  • 14
  • 2
    Also the `s` in `"%[^\n]s"` is more than just redundant, `scanf()` will try to match the next byte against an `s`, which must fail as the next byte is a newline unless the end of file has been reached. – chqrlie Feb 27 '22 at 10:27
  • 1
    The `scanf` conversion stops at the first character it cannot convert, which is typically (but not necessarily) a space or a newline, and that character remains in the input buffer. It will be read by the *next* `scanf()`. Most format specifiers automatically filter leading whitespace characters from the input, but `%c` and `%[]` and `%n` do not. You can instruct `scanf` to do so by adding a space just before the `%`. Whitespace in the format string is meaningful: sometimes redundant, but *trailing* whitespace can be harmful. – Weather Vane Feb 27 '22 at 10:28
  • @chqrlie Will it though? Wouldn't it be `"%[^\n]%s"` for that to be the case? – aulven Feb 27 '22 at 10:42
  • Oh right, it will try to match it against the character `s` not a string, – aulven Feb 27 '22 at 10:44
  • @melonduofromage: characters in the `scanf()` format string that are not part of a conversion specification, nor whitespace, are matched against the stream contents. No undefined behavior because of the trailing `s`, but if one does not specify `%199[^\n]`, a line longer than 199 bytes will cause undefined behavior as `scanf()` will store bytes beyond the end of the 200 byte destination array. – chqrlie Feb 27 '22 at 10:46
  • @WeatherVane Which is guaranteed to result in an another question as soon as OP tries to use something like `fgets` after the `scanf`s – aulven Feb 27 '22 at 10:49
  • 1
    `scanf()` is full of traps and pitfalls. It takes implementing it and passing a validation suite to fully understand its intricacies. This function is painfully inadequate for beginners to read user contents. A systematic combination of `fgets()` and `sscanf()` is a more sensible approach, with an opportunity for error handling and recovery. – chqrlie Feb 27 '22 at 10:51
  • @melonduofromage I did not suggest they should. An understanding of how the input functions handle incoming whitespace, and the significance of whitespace in the `scanf` format string, is crucial to mastering user input. The functions all work differently, and the format specifiers also work differently. – Weather Vane Feb 27 '22 at 14:58