%[^\n] 在 scanf() 格式字符串中是啥意思
Posted
技术标签:
【中文标题】%[^\\n] 在 scanf() 格式字符串中是啥意思【英文标题】:What does %[^\n] mean in a scanf() format string%[^\n] 在 scanf() 格式字符串中是什么意思 【发布时间】:2014-10-27 22:03:29 【问题描述】:我在这个网站上看到:fscanf(fin, "%[^\n]", &p);
可用于从我的输入文件(fin
)读取该字符类型指针(*p
)中的所有字符,直到第一次输入命中。在某些输入上它可以正常工作,但在其他输入上却不能。
这是我应该处理的输入,但我不能:
(((zahar 100 ou 3) 5 unt 100 nuca 200) 4 (lapte 200 cacao 50 zahar 100)3)20
这是我的全部代码:
#include <string.h>
#include <stdio.h>
FILE *fin, *fout;
int main()
fin = fopen("reteta.in", "r");
fout = fopen("reteta.out", "w");
char *p;
p = new char[1001]();
fscanf(fin, "%[^\n]", &p);
fprintf(fout, "%s", &p);
return 0;
【问题讨论】:
匹配无限多个字符但不匹配\n
,并将它们放入对应参数指向的char[]
。 (因此它属于char*
类型,不是char**
。
谷歌搜索fscanf
将我带到msdn.microsoft.com/en-us/library/kwwtf9ch.aspx,只需点击三下鼠标。
请注意 new char[1001]();
不是 C -- 它是 C++ 代码。
尾随的()
是什么?
您应该将p
传递给fscanf()
,而不是&p
。您几乎肯定应该在fout
的输出中包含一个换行符。您应该在打印之前检查输入是否成功。 FILE *
变量应该是 main()
的本地变量,而不是全局变量。可以说,您应该在退出之前关闭文件(尽管运行时系统会自动关闭它们,但通常认为关闭您打开的文件是更好的做法 - 这在长时间运行的程序中确实很重要,尽管它不会损害这一点一)。
【参考方案1】:
%[
表示法引入了一种称为“扫描集”的东西,它有点像正则表达式(但没有那么强大)。
在您的具体示例中,这意味着格式说明符指示 scanf
继续扫描与 \n
以外的任何字符匹配的字符(遇到不匹配的字符将终止扫描)。
来自 C11 标准:
转换说明符包括所有后续字符 格式字符串,直到并包括匹配的右括号 (])。这 括号(扫描列表)之间的字符组成扫描集, 除非左括号后的字符是抑扬符 (^),in 在这种情况下,扫描集包含所有未出现在 抑扬符和右括号之间的扫描列表。
即使将它与正则表达式进行比较也是在拉伸它:标准只是简单地说:“匹配一组预期字符中的非空字符序列”。
Jonathan Leffler 发现您的代码的真正问题是:
fscanf(fin, "%[^\n]", &p);
^
删除&
,因为您想传递 p,而不是“p 的地址”。
【讨论】:
这就是它的意思,读取从 scanf 到 \n 字符的所有内容。我看到你在说同样的话,或者我不明白。如果它做到了,为什么它不适用于该输入? @MihneaGafton 你没有解释它在什么方面不起作用。究竟发生了什么?它与您的预期有何不同? 对不起,没有正确解释,当我尝试使用该输入编译该代码时,它会在控制台上给我类似无限循环的错误。【参考方案2】:%
introduces a format-specifier, [
表示它是一个扫描集并打开它,^
在扫描集中的第一个位置从“匹配所有”反转为“匹配所有不 in",\n
是换行符,]
关闭扫描集。
因此,它意味着:无限匹配许多不是\n
的字符,并将它们放入参数指向的char[]
中。
因此该参数必须具有 char*
类型。&p
恰好是一个过多的地址,并且它指向的缓冲区 (new char[1001]
) 是无限订单量级太小了。
限制匹配的长度(通过在扫描集和%
之间放置 1000)。
或者,更好的是,使用fgets
。
其他要点:
您的缓冲区应该是堆栈分配的,因为它足够小:
char buf[1001];
或者,至少使用智能指针,这样你就不会忘记delete []
它:
std::unique_ptr<char> p = new char[1001];
为什么要对它进行值初始化?那是多余的。使用new char[1001]
而不是new char[1001]()
。
不要忘记检查fscanf
的返回值,它应该是成功的赋值数。
C++(和 C99)在 main
的末尾有一个隐式的 return 0;
。
你真的应该关闭你打开的所有文件 (fopen
->fclose
)。
【讨论】:
“限制匹配的长度(通过在扫描集和 % 之间放置 1000)。”这意味着像fscanf(fin, "%1000[^\n]", &p);
这样写,我试过了,它向我显示了一个类似控制台错误的无限循环,类似于第一种情况。
@jonathan:我不认为“infinitely”是一个错字,虽然“infinitely”更准确一些,但它并没有强调无限的本质。
@MihneaGafton: ??无论如何,您是否阅读过关于额外的&
存在错误的部分?
@BenVoigt:我同意这种变化可能会引起争议——事实上,既然你提出了质疑,那就是有争议的。这取决于一个人如何理解“无限”。宇宙中没有足够的基本粒子来存储无限数量的字符,因此字符串无法容纳无限数量的字符。只有当“无限”字符数为 1000 或更少时,它才是安全的。如果 Deduplicator 对象,他可以“无限”恢复。
@Deduplicator 我做了,不工作,谢谢。一旦我弄清楚如何将此问题标记为已解决,我就会这样做。以上是关于%[^\n] 在 scanf() 格式字符串中是啥意思的主要内容,如果未能解决你的问题,请参考以下文章