Reputation: 15042
I know about the introduction of the scanset with the [
conversion specifier which subsequent indicate characters to match or not to match with an additional interposition of the ^
symbol.
For this, in ISO/IEC 9899/1999 (C99) is stated:
The characters between the brackets (the scanlist) compose the scanset, unless the character after the left bracket is a circumflex (^), in which case the scanset contains all characters that do not appear in the scanlist between the circumflex and the right bracket.
So, the expression [^\n]
means, that it is scanning characters until a \n
character is found in the according stream, here at scanf()
, stdin
. \n
is not taken from stdin
and scanf()
proceeds with the next format string if any remain, else it skips to the next C statement.
Next there is the assignment-suppression-operator *
:
For this, in ISO/IEC 9899/1999 (C99) is stated:
Unless assignment suppression was indicated by a *, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result.
Meaning in the case of f.e. scanf("%*100s",a);
that a sequence of 100 characters is taken from stdin
unless a trailing white-space character is found but not assigned to a
if a
is a proper-defined char
array of 101 elements (char a[101];
).
But what does now the format string "%*[^\n]"
in a scanf()-statement achieve?
Does \n
remain instdin
?
How do assignment supressor *
and negated scanset [^
work together?
Does it mean, that:
*
all characters matching to this format string are taken from stdin
, but are sure not assigned?, and \n
isn't taken from stdin
but it is used to determine the scan-operation for the according format string?I know what each of those [^
and *
do alone, but not together. The question is what is the result of the mix of those two together, incorporated with the negated scanset of \n
.
I know that there is a similar question on Stack Overflow which covers the understanding of %[^\n]
only, here: What does %[^\n] mean in a scanf() format string. But the answers there do not help me with my problem.
Upvotes: 5
Views: 813
Reputation: 361625
%[^\n]
reads up to but not including the next \n
character. In plain English, it reads a line of text. Normally, the line would be stored in a char *
string variable.
char line[SIZE];
scanf("%[^\n]", line);
The *
modifier suppresses that behavior. The line is simply discarded after being read and no variable is needed.
scanf("%*[^\n]");
*
doesn't alter how the input is processed. In either case, everything up to but not including the next \n
is read from stdin. Assuming no I/O errors, it is guaranteed that the next read from stdin will see either \n
or EOF
.
Which
scanf()
statement should I use if I want to read and thereafter discard every character instdin
including the\n
character?
Add %*c
to also consume the \n
.
scanf("%*[^\n]%*c");
Why %*c
instead of just \n
? If you used \n
it wouldn't just consume a single newline character, it would consume any number of spaces, tabs, and newlines. \n
matches any amount of whitespace. It's better to use %*c
to consume exactly 1 character.
// Incorrect
scanf("%*[^\n]\n");
See also:
Could I use
fflush()
instead?
No, don't. fflush(stdin)
is undefined.
Isn't the negated scanset of
[\n]
completely redundant becausescanf()
terminate the scan process of the according format string at first occurrence of a white space character by default?
With %s
, yes, it will stop reading at the first whitespace character. %s
only reads a single word. %[^\n]
, by contrast, reads an entire line. It will not stop at spaces or tabs, only newlines.
More generally, with square brackets only the exact characters listed are relevant. There is no special behavior for whitespace. Unlike %s
it does not skip leading whitespace, nor does it stop processing early if it encounters whitespace.
Upvotes: 5
Reputation: 20244
%[^\n]
tells scanf
to read everything until a newline character ('\n'
) and store it in its corresponding argument.%*[^\n]
tells scanf
to read everything until a newline character ('\n'
) and discard it instead of storing it.Examples:
Hi there\n
into scanf("%[^\n]", buffer);
results in buffer
content Hi there
and leftover stdin
content \n
Hi there\n
into scanf("%*[^\n]");
results in Hi there
getting scanned and discarded from the stdin
and leftover stdin
content \n
.Note that both %[^\n]
and %*[^\n]
will fail if the first character that it encounters is a \n
character. Once it fails, the stdin
is left untouched and the scanf
returns resulting in the rest of the format string getting ignored.
If you wish to remove clear a line of stdin
upto and including the newline character using scanf
, use
scanf("%*[^\n]"); /* Read and discard everything until a newline character */
scanf("%*c"); /* Discard the newline character */
Upvotes: 1
Reputation: 62797
Since it doesn't appear to be covered, the working way to read everything before newline, and then the newline, is:
scanf("%*[^\n]%*c");
%*[^\n]
reads and discards until next character is newline%*c
reads and discards just one character, which per above will be newlineYou could also read the newline with %c
to a variable and see if you really get a newline successfully, but you could also just directly check for EOF or error directly and not bother with this this.
Upvotes: 1
Reputation: 15576
Does
\n
remain instdin
?
Yes, it does.
But what does now the format string
"%*[^\n]"
in ascanf()
-statement achieve?
It reads all characters from the input stream until it reaches a newline and discards them, without removing the newline from the input stream.
By using
*
all characters matching to this format string are taken fromstdin
, but are not assigned?
Correct.
\n
isn't taken fromstdin
but it is used to determine the scan-operation for the according format string?
Exactly. When \n
is reached, most scanf
s use ungetc
to push the character back to the input stream.
I know what each of those
[^
and*
do alone, but not together.
Putting *
before [^
does exactly what [^
alone does except that it does not read the input into an argument and instead discards it.
If you want to discard the \n
afterwards, use this format string:
"%*[^\n]%*c"
Upvotes: 2