All 3 format begin with "%[^\n]"
.
"%[^\n]"
is poor code2 that lacks a width limit and is susceptible to buffer overrun. Use a width limit like "%99[^\n]"
with char s[100];
.
"%[...]"
does not consume leading whitespace like many other specifiers.
This specifier directs reading input until a '\n'
1 is encountered. The '\n'
is put back into stdin
. All other characters are saved in the matching destination's array s
.
If no characters were read (not counting the '\n'
), the specifier fails and scanf()
returns without changing s
- rest of the format is not used. No null character appended.
If characters were read, they are saved and a null character is appended to s
and scanning continues with the next portion of the format.
"\n"
acts just like " "
, "\t"
, "any_white_space_chracter"
and reads and tosses 0 or more whitespace characters. It continues to do so until a non-white-space1 is read. That non-whitespace character is put back into stdin
.
Given line buffered input, this means a line with non-whitespace following input is needed to see the next non-whitespace and allow scanf()
to move on.
With scanf()
, a "\n"
at the end of a format is bad and caused OP's problem.
"%*c"
reads 1 character1 and throws it away - even if it is not a '\n'
. This specifier does not contribute to the return count due to the '*'
.
A better alternative is to use fgets()
.
char s[100];
if (fgets(s, sizeof s, stdin)) {
s[strcspn(s, "\n")] = '\0'; // To lop off potential trailing \n
A lesser alternative is
char s[100] = { 0 };
scanf("%99[^\n]", s);
// With a separate scanf ....
scanf("%*1[\n]"); // read the next character if it is a \n and toss it.
1 ... or end-of-file or rare input error.
2 IMO, worse than gets()
.