C中`"%[^\n]"`、`"%[^\n]\n"`和`"%[^\n]%*c"`的区别以及它们的工作原理是什么?

5

我在其他地方找不到答案。

%[^\n] - 运行这个程序时,scanf正在获取输入并在我按下回车后终止。( 可能会在输入系统中留下\n

%[^\n]\n - 这个程序能够获取输入,但是 scanf 不像上面的那一个立即在我按下回车后终止。我按下更多的回车键,它会产生更多的新行。 当我输入一个字符然后按回车键时,它最终终止。例如:

int main(void)
{
    char s[100];

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

    printf("%s", s);

    return 0;
}
结果:

输入图像描述

最后一个:

%[^\n]%*c - 当我输入并按下回车时,scanf 立即终止。

这三个是如何工作的,它们之间的区别是什么?


是的,但我想知道这三个实际上是如何工作的,我想知道它们背后的逻辑。为什么它们会以这样的方式行事? - Ali Uyanık
可能是重复的问题:scanf正则表达式-C - Caleb
1个回答

4
所有3种格式都以"%[^\n]"开头。 "%[^\n]"是糟糕的代码2,缺乏宽度限制并容易发生缓冲区溢出。应该使用带有宽度限制的格式,例如"%99[^\n]"char s[100];配合使用。 "%[...]"不像许多其他格式说明符一样消耗前导空格。
此说明符指示读取输入直到遇到'\n'1'\n'被放回到stdin中。所有其他字符都保存在匹配目标的数组s中。
如果没有读取任何字符(不包括'\n'),则说明符失败,并且scanf()返回不更改s - 格式的其余部分不被使用。不附加null字符
如果读取了字符,则将其保存,并在s中附加null字符,并继续扫描下一个格式部分。
"\n"的作用类似于" ""\t""any_white_space_chracter",它读取并抛弃0个或多个空白字符。它会继续这样做,直到读取到非空格1。那个非空格字符被放回到stdin中。
对于行缓冲输入,这意味着需要有一个跟随输入的非空格行才能看到下一个非空格,并允许scanf()继续执行。
使用scanf()时,格式结尾的"\n"不好的,会导致问题发生。
"%*c"读取1个字符1并将其丢弃 - 即使它不是'\n'也是如此。由于'*',该说明符不会对返回计数产生贡献。
更好的选择是使用fgets()
char s[100];
if (fgets(s, sizeof s, stdin)) {
   s[strcspn(s, "\n")] = '\0';  // To lop off potential trailing \n

一个不太好的替代方法是:
char s[100] = { 0 };
scanf("%99[^\n]", s);
// With a separate scanf ....
scanf("%*1[\n]");  // read the next character if it is a \n and toss it.

1 ... 或者文件结束或罕见的输入错误。

2 在我看来比 gets() 更糟糕。


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