在C语言中,%[^\n]表示读取输入直到遇到换行符为止。

18

%[^\n]在C语言中是什么意思?我在一个使用scanf将多个单词输入到字符串变量中的程序中看到了它。但我不理解,因为我以前学过scanf不能接收多个单词。

以下是代码:

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

int main() {
    char line[100];
    scanf("%[^\n]",line);
    printf("Hello,World\n");
    printf("%s",line);
    return 0;
}

scanf()的文档中,它被称为“扫描集”。 - Jonathan Leffler
5
scanf("%[^\n]",line)存在以下常见问题:1)它不限制输入,因此,在这种情况下,输入100个字符或更多的文本可能会溢出"line[]"缓冲区。2)如果遇到的第一个字符是'\n',则对"line[]"不做任何更改且函数返回0。3)'\n' 仍然留在stdin中。为了避免未来的问题,请不要使用scanf("%[^\n]",line);,而要使用fgets()进行研究和使用。 - chux - Reinstate Monica
1
在 C 语言中,%[^\n] 没有任何意义。在 scanf 格式化语言(C 中使用的)中,它意味着您的代码已经打开了一个非常大的漏洞,容易受到溢出攻击。学习 scanf 格式化语言并不等于学习 C 语言。事实上,这样做会妨碍您学习 C 语言。 - William Pursell
当你“了解到scanf无法接受多个单词”时,这是指%s标志。在你上面的代码中,你正在使用%[ - Jann Poppinga
5个回答

24

[^\n]是一种正则表达式。

  • [...]: 它匹配在...中给定的字符集中的一个非空字符序列(称为“扫描集”)。
  • ^表示扫描集“否定”的意思:即由其补集给出。
  • ^\n:扫描集是除了\n之外的所有字符。

此外,fscanf(和scanf)将读取与格式匹配的最长输入字符序列。

因此,scanf("%[^\n]", s);将读取所有字符直到达到\n(或EOF),并将它们放入s中。在C中,这是一种常见的读取整行的习惯用法。

另请参见§7.21.6.2 The fscanf function


如果我们使用除了 \n 之外的任何其他字符,它会起到相同的作用吗? - Salman Sadi
@SalmanSadi:你是指像这样的东西吗 scanf("[^a]", s);?它会读取整个字符串直到字母 a - md5
1
请注意,如果要读取的第一个字符是“a”,则 scanf("[^a]", s); 不会更改 s。在这种情况下,请不要期望 s 具有值 "" - chux - Reinstate Monica
1
这有点像正则表达式,就像scanf中的所有内容都有点像正则表达式。 - Antti Haapala -- Слава Україні
通常情况下,读取整行是一种常见的习惯用法,但它无法完全读取整行,会在stdin中留下'\n'。 - chux - Reinstate Monica

8

scanf("%[^\n]",line); 是一种有问题的读取的方式。它比 gets() 更糟糕。

C语言中将定义为:

文本流是由字符按顺序组成的,每行包含零个或多个字符以及一个终止的换行符。最后一行是否需要换行符是由具体实现定义的。

scanf("%[^\n]", line)使用了格式控制字符串"%[^\n]"。它扫描所有与扫描集合^\n匹配的字符,如果没有读取到任何字符,则该格式化说明符执行失败并且scanf()返回,并且line保持不变。如果至少读取到一个字符,则会读取和保存所有匹配的字符,最后加上一个null字符

扫描集合^\n表示所有不是(因为有一个'^''\n'的字符。

'\n'未被读取

scanf("%[^\n]",....未能读取到一个换行符'\n'。该字符将保留在stdin中,整个都没有被读取。

缓冲区溢出

如果读取的字符数超过99个,则可能导致未定义行为(UB)。

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

空行不执行操作

当行只包含"\n"时,scanf("%[^\n]",line);返回一个0而不会设置line[] - 没有附加任何null字符。这可能导致后续代码使用未初始化的line[]而引起未定义的行为'\n'仍然在stdin中。

未检查返回值的失败

scanf("%[^\n]",line);假定输入成功。更好的代码应该检查scanf()的返回值。


建议

不要使用scanf(),而是使用fgets()来读取一个的输入。

#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.
  }

fgets() 方法也有其局限性。例如,它无法读取嵌入的null字符

处理用户输入(可能具有敌对性)是具有挑战性的。


4
scanf("%[^\n]",line);

意思是:扫描直到\n或回车键。

...或者输入结束,即CTRL+D - Ed Heal

2
scanf("%[^\n]",line);

将读取用户输入,直到按下“Enter”键或添加换行符(\n),并将其存储在名为line的变量中。

-2

问题:C语言中的%[^\n]是什么意思?

  1. 基本上\n命令会将输出打印在下一行,但在C语言中会给出空数据Null,接着出现上述问题。

  2. 因此,为了去除不需要的数据或空数据,需要添加补充/否定符号[^\n]。它会提供直到下一行的所有字符,并保留所定义表达式中的数据。

  3. 这意味着它是来自垃圾桶中的补充数据或重写数据。

例如:

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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接