5

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:

  1. By using * all characters matching to this format string are taken from stdin, but are sure not assigned?, and
  2. \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.

  • The asterisk `*` is a standard prefix character that have a special meaning for all formats. See e.g. [this `scanf` (and family) reference](https://en.cppreference.com/w/c/io/fscanf) for details. – Some programmer dude Oct 28 '19 at 10:58
  • 1
    Figure out what `"%[^\n]"` does. `"%*[^\n]"` does exactly the same thing, except that the result is not stored anywhere. The End. – Sam Varshavchik Oct 28 '19 at 10:58
  • @SamVarshavchik I know what `%[^\n]`does, i explained it myself in the question. the question is: what does `%*[^\n]` exaclty? Is `\n` left in `stdin` after its use? – RobertS supports Monica Cellio Oct 28 '19 at 11:02
  • 1
    @RobertS So then question really is, "what does the `*` character do in a `scanf` format string?" – Some programmer dude Oct 28 '19 at 11:08
  • @Someprogrammerdude No, 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`. – RobertS supports Monica Cellio Oct 28 '19 at 11:11
  • 2
    The asterisk does exactly the same no matter the format string, it can be combined with *any* format specifier, though it makes no sense for the `n` specifier. That means `%*[^\n]` does almost exactly the same as `%[^\n]`, with the only difference being that the asterisk causes `scanf` to not write the data to a string (it throws away what it read). If you have the knowledge of both separately, you already have the knowledge of both combined. – Some programmer dude Oct 28 '19 at 11:13
  • Whether \n is left in stdin does not depend on the inclusion of * in the format specifier. If \n is left in stdin without the * present, then the same occurs with * present. Ditto for the opposite. If you know what happens without the * then you know what happens with it, too. This shouldn't be difficult to understand. Very simple concept. – Sam Varshavchik Oct 28 '19 at 11:47
  • 1
    Note: In `scanf("%*100s",a);`, the variable `a` is completely redundant. The statement is equivalent to `scanf("%*100s");` which will scan a string upto a whitespace character or upto 100 characters (whichever comes first) and will discard it – Spikatrix Oct 28 '19 at 12:29
  • @user3121023 that was the information i was looking for. Isn´t the use of the scanset `[\n]` redundant, because `scanf()` terminates the process of consuming characters at the first occurence of any white space character by default? – RobertS supports Monica Cellio Oct 28 '19 at 13:10
  • @Someprogrammerdude This is what i have asked for. I´ve read the relative text parts several times in C99, as well considered several other websites but i quite did not understand it. Anyway, Isn´t the negated scanset of `[\n]` redundant? `scanf()` terminate the scan process of the according format string at first occurence of a white space character by default, or am i thinking wrong? – RobertS supports Monica Cellio Oct 28 '19 at 13:22
  • 1
    You're correct that `scanf` normally read white-space delimited "words". So if the user gives a multi "word" sentence as input that would lead e.g. `%s` to read only the *first* "word", not the whole line. Scan-sets matches (possibly inverted) exact characters, not white-space in general like otherwise. – Some programmer dude Oct 28 '19 at 13:26

4 Answers4

5

%[^\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 in stdin 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 because scanf() 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.

John Kugelman
  • 307,513
  • 65
  • 473
  • 519
2

Does \n remain in stdin?

Yes, it does.

But what does now the format string "%*[^\n]" in a scanf()-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 from stdin, but are not assigned?

Correct.

\n isn't taken from stdin but it is used to determine the scan-operation for the according format string?

Exactly. When \n is reached, most scanfs 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"
S.S. Anne
  • 13,819
  • 7
  • 31
  • 62
  • Thank you very much for your information, JL2210. One question more: Isn´t the negated scanset of `[\n]` completely redundant because `scanf()` terminates the process of consuming characters of the according format string at first occurence of a white space character by default? – RobertS supports Monica Cellio Oct 28 '19 at 13:12
  • 1
    @RobertS No, `%[` and `%c` don't eat up whitespace. – S.S. Anne Oct 28 '19 at 13:18
1

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 newline

You 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.

hyde
  • 50,653
  • 19
  • 110
  • 158
  • Thank you very much, hyde. I have one question more: Isn´t the scanset of `[\n]` completely redundant because `scanf()` terminate the scan process of the according format string at first occurence of a white space character by default? – RobertS supports Monica Cellio Oct 28 '19 at 13:15
  • @RobertS Not sure what you mean, but`%c` does not skip whitespace, and also remaining part of line might contain anything, not just whitespace, and purpose here is to get rid of it all. – hyde Oct 28 '19 at 16:30
1
  • %[^\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:

  • Input Hi there\n into scanf("%[^\n]", buffer); results in buffer content Hi there and leftover stdin content \n
  • Input 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 */
Spikatrix
  • 19,378
  • 7
  • 34
  • 77
  • Thank you very much. I have one question more: Isn´t the negated scanset of `[\n]` redundant because `scanf()` terminates the process of consuming characters of the according format string at first occurence of a white space character by default? – RobertS supports Monica Cellio Oct 28 '19 at 13:13
  • @RobertS `%[^\n]` will stop scanning until a newline character (or `EOF`), not a space unlike `%s` and several other format specifiers – Spikatrix Oct 28 '19 at 13:22