【问题标题】:What does %[^\n] mean in C?%[^\n] 在 C 中是什么意思?
【发布时间】:2016-09-11 01:01:20
【问题描述】:

%[^\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()等人的文档中称为扫描集
  • scanf("%[^\n]",line); 的常见问题 1) 它不限制输入,因此在这种情况下,输入文本 100 个字符或更多字符会溢出line[] 缓冲区。 2) 如果遇到的 第一个 字符是'\n',则 nothing 关于line[] 进行更改,并且函数返回 0。 3) '\n' 保留在 @987654331 @。保存自己未来的问题,不要使用scanf("%[^\n]",line); 研究并改用fgets()
  • 在 C 中,%[^\n] 没有任何意义。在 scanf 格式化语言(由 C 使用)中,这意味着您的代码已经打开了一个非常大的溢出漏洞利用漏洞。学习 scanf 格式化语言不是学习 C。确实,这样做是学习 C 的障碍。
  • 当你“得知 scanf 不能接受多个单词”时,指的是%s 标志。在上面的代码中,您使用的是%[

标签: c string


【解决方案1】:

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

  • [...]:它匹配 scanset 中的非空字符序列(... 给出的一组字符)。
  • ^ 表示扫描集是“否定的”:它由它的补码给出。
  • ^\n:扫描集是除\n之外的所有字符。

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

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

另见§7.21.6.2 The fscanf function

【讨论】:

  • 另一件事,如果我们使用除 \n 以外的任何其他字符,它的工作方式是否相同?
  • @SalmanSadi:你的意思是像scanf("[^a]", s);这样的东西吗?它将读取整个字符串直到字母a
  • @md5 请注意,如果要读取的第一个字符是 'a'scanf("[^a]", s); 将不会更改 s。在这种情况下,不要期望 s 具有 "" 的值。
  • 这是一种正则表达式,是的,就像 scanf 中的其他所有内容一样,也是一种正则表达式。
  • “读一整行是常用的成语”--> 除了读不到整行行,'\n'留在stdin中。
【解决方案2】:

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

C 将 line 定义为:

文本流是组成的有序字符序列,每行由零个或多个字符加上一个终止换行符组成。最后一行是否需要终止换行符是实现定义的。

scanf("%[^\n]", line) 具有说明符 "%[^\n]"。它扫描无限数量的与 scan-set ^\n 匹配的字符。如果没有读取,则说明符失败,scanf() 返回,line 不变。如果至少读取了一个字符,则读取并保存所有匹配的字符,并附加一个 空字符

扫描集^\n 暗示所有不是的字符(由于'^''\n'


'\n' 未被读取

scanf("%[^\n]",.... 无法读取 换行符 '\n'。它仍保留在stdin 中。整行未被读取。

缓冲区溢出

如果读取超过 99 个字符,以下会导致未定义的行为 (UB)。

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

在空行上什么都不做

当该行仅包含 "\n" 时,scanf("%[^\n]",line); 返回一个 0 而不设置 line[] - 不附加 空字符。如果后续代码使用未初始化的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() 方法也有其局限性。例如(读取嵌入的空字符)。

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

【讨论】:

    【解决方案3】:
    scanf("%[^\n]",line);
    

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

    【讨论】:

      【解决方案4】:
      scanf("%[^\n]",line);
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-02-04
        • 2015-07-15
        • 1970-01-01
        • 1970-01-01
        • 2013-03-09
        • 2010-12-26
        • 2020-02-23
        相关资源
        最近更新 更多