16

What does %[^\n] mean in C? I saw it in a program which uses scanf for taking multiple word input into a string variable. I don't understand though because I learned that scanf can't take multiple words.

Here is the code:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char line[100];
    scanf("%[^\n]",line);
    printf("Hello,World\n");
    printf("%s",line);
    return 0;
}
Robert Columbia
  • 6,313
  • 15
  • 32
  • 40
Salman Sadi
  • 171
  • 1
  • 2
  • 5
  • It's called a _scan set_ in the documentation for [`scanf()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/scanf.html) et al. – Jonathan Leffler Sep 11 '16 at 01:26
  • 5
    Common problems with `scanf("%[^\n]",line);` 1) It does not limit input, so in this case, input text 100 characters or more can overflow the `line[]` buffer. 2) If the _first_ character encountered is a `'\n'`, _nothing_ is changed about `line[]` and the function returns 0. 3) The `'\n'` remains in `stdin`. Save yourself future problems, do not use `scanf("%[^\n]",line);` Research and use `fgets()` instead. – chux - Reinstate Monica Sep 11 '16 at 01:50
  • 1
    In C, `%[^\n]` has no meaning. In the scanf formatting language (which is used by C) it means that your code has opened a very large vulnerability to an overflow exploit. Learning the scanf formatting language is *not* learning C. Indeed, doing so is an impediment to learning C. – William Pursell Mar 25 '21 at 14:20
  • When you "learned that scanf can't take multiple words", that referred to the `%s` flag. In your code above, you're using `%[`. – Jann Poppinga Apr 08 '21 at 14:57

5 Answers5

22

[^\n] is a kind of regular expression.

  • [...]: it matches a nonempty sequence of characters from the scanset (a set of characters given by ...).
  • ^ means that the scanset is "negated": it is given by its complement.
  • ^\n: the scanset is all characters except \n.

Furthermore fscanf (and scanf) will read the longest sequence of input characters matching the format.

So scanf("%[^\n]", s); will read all characters until you reach \n (or EOF) and put them in s. It is a common idiom to read a whole line in C.

See also §7.21.6.2 The fscanf function.

md5
  • 23,373
  • 3
  • 44
  • 93
8

scanf("%[^\n]",line); is a problematic way to read a line. It is worse than gets().

C defines line as:

A text stream is an ordered sequence of characters composed into lines, each line consisting of zero or more characters plus a terminating new-line character. Whether the last line requires a terminating new-line character is implementation-defined.

The scanf("%[^\n]", line) has the specifier "%[^\n]". It scans for unlimited number of characters that match the scan-set ^\n. If none are read, the specifier fails and scanf() returns with line unaltered. If at least one character is read, all matching characters are read and saved and a null character is appended.

The scan-set ^\n implies all character that are not (due to the '^') '\n'.


'\n' is not read

scanf("%[^\n]",.... fails to read a new line character '\n'. It remains in stdin. The entire line is not read.

Buffer overflow

The below leads to undefined behavior (UB) should more than 99 characters get read.

char line[100];
scanf("%[^\n]",line);  // buffer overflow possible

Does nothing on empty line

When the line consists of only "\n", scanf("%[^\n]",line); returns a 0 without setting line[] - no null character is appended. This can readily lead to undefined behavior should subsequent code use an uninitialized line[]. The '\n' remains in stdin.

Failure to check the return value

scanf("%[^\n]",line); assumes input succeeded. Better code would check the scanf() return value.


Recommendation

Do not use scanf() and instead use fgets() to read a line of input.

#define EXPECTED_INPUT_LENGTH_MAX 49
char line[EXPECTED_INPUT_LENGTH_MAX + 1  + 1  + 1];
//                                    \n + \0 + extra to detect overly long lines 

if (fgets(line, sizeof line, stdin)) {
  size_t len = strlen(line);
  // Lop off potential trailing \n if desired.
  if (len > 0 && line[len-1] == '\n') {
    line[--len] = '\0';
  }
  if (len > EXPECTED_INPUT_LENGTH_MAX) {
    // Handle error
    // Usually includes reading rest of line if \n not found.
  }

The fgets() approach has it limitations too. e.g. (reading embedded null characters).

Handling user input, possible hostile, is challenging.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
4
scanf("%[^\n]",line);

means: scan till \n or an enter key.

vitaly-t
  • 24,279
  • 15
  • 116
  • 138
2
scanf("%[^\n]",line);

Will read user input until enter is pressed or a newline character is added (\n) and store it into a variable named line.

Bill Wang
  • 140
  • 13
-2

Question: what is %[^\n] mean in C?

  1. Basically the \n command prints the output in the next line, but in case of C gives the Null data followed by the above problem only.

  2. Because of that to remove the unwanted data or null data, need to add Complement/negotiated symbol[^\n]. It gives all characters until the next line and keeps the data in the defined expression.

  3. Means it is the Complemented data or rewritten data from the trash

EX:

char number[100]; //defined a character ex: StackOverflow
scanf("%[^\n]",number); //defining the number without this statement, the 
character number gives the unwanted stuff `���`
printf("HI\n"); //normaly use of printf statement
printf("%s",number); //printing the output
return 0;