What does %[^\n] mean in C?

前端 未结 4 828
滥情空心
滥情空心 2020-12-12 23:12

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 tho

相关标签:
4条回答
  • 2020-12-12 23:37

    scanf("%[^\n]",line); is a problematic way to read a line. It 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 is read, all matching are read and saved. 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 chracter '\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[]. This can readily lead to undeifned bevaior 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. (embedded null chracters).

    Handling user input, possible hostile, is challenging.

    0 讨论(0)
  • 2020-12-12 23:38

    [^\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.

    0 讨论(0)
  • 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.

    0 讨论(0)
  • 2020-12-12 23:51
    scanf("%[^\n]",line);
    

    means: scan till \n or an enter key.

    0 讨论(0)
提交回复
热议问题