使用scanf()读取一行不好?
我的一位朋友建议,使用使用scanf()读取一行不好?,c,scanf,stdio,C,Scanf,Stdio,我的一位朋友建议,使用fgets()读取一行作为输入比使用上面的语句中的scanf()要好得多。他有理由吗?可以安全使用,因为它避免了问题,只扫描num-1字符数 从流中读取字符并将其作为C字符串存储到str中,直到读取(num-1)个字符或到达换行符或文件结尾,以先发生的为准 这里的第二个参数num是要复制到str中的最大字符数(包括终止的空字符) 例如,假设在您的代码中,字符串数组的容量仅为5chars,如下所示 scanf(" %[^\n]",line); 使用上述代码,如果从fp输入的
fgets()
读取一行作为输入比使用上面的语句中的scanf()
要好得多。他有理由吗?可以安全使用,因为它避免了问题,只扫描num-1
字符数
从流中读取字符并将其作为C字符串存储到str中,直到读取(num-1)个字符或到达换行符或文件结尾,以先发生的为准
这里的第二个参数num
是要复制到str中的最大字符数(包括终止的空字符)
例如,假设在您的代码中,字符串数组的容量仅为5
chars,如下所示
scanf(" %[^\n]",line);
使用上述代码,如果从fp
输入的字符长于4
字符,fgets()
将首先读取4
字符,然后追加\0
(,并丢弃其他额外的输入字符,只在str[]
中存储五个字符)
而
scanf(“%[^\n]”,str)
将一直读取,直到找不到\n
为止,如果输入字符串较长,则4
charsscanf()
将导致(因为scanf
将尝试访问str[]
中超出最大索引4
的内存) 简单地说:是的,fgets
是一个更好的选择
我看了看你的scanf
格式说明符,我很困惑。准确理解它的功能需要花一些时间阅读man
页面
此外,您的scanf
代码容易发生缓冲区溢出
保持简单,您将减少维护成本,避免难以发现的错误 C常见问题解答对
scanf
的问题有一些详细的解释:
更一般地说,scanf
是为相对结构化、格式化的输入而设计的(其名称实际上来源于“扫描格式化”)。如果你注意,它会告诉你它是成功了还是失败了,但它只能告诉你失败的大致位置,而不能告诉你失败的方式或原因。您几乎没有机会执行任何错误恢复
有关详细信息,请参见。
fgets
将比此scanf
更好。
如OP中所述,scanf
可能存在以下问题
1) @Grijesh建议的缓冲区溢出
2) 可能接下来的
scanf
将不起作用,因为换行符保留在输入流中。(如果缺少空格)是的,fgets是从标准输入读取行的更好、更安全的方法
此外,代码的可读性会更好。请看您给出的scanf声明
任何第二个看到它的人都会被彻底弄糊涂。但是,尽管FGET的可读性更强,而且更容易理解。不要使用FGET(…),而是使用以下代码段:
char str[5];
fgets (str, 5, fp); //5 =you have provision to avoid buffer overrun
嗯,这是因为
scanf
不会强制您限制输入大小,但是fgets
会
如果您阅读了文档并正确使用了scanf
,这里的差别其实不大:
字符行[256];
scanf(“%255[^\n]%*c”,第行);//%*c以删除尾随\n
fgets(第256行,标准输入)
请注意,我从scanf
格式字符串中删除了前导空格。
我稍后再谈这个问题
这两种情况都确保了我们不会阅读过多
但是,从安全角度来看,我们需要考虑:
强制您指定尺寸fgets
- 在
上,您需要记住将阵列容量设置为-1scanf
为您执行此操作,因此您实际上通过了容量(或更少)fgets
- “这个格式到底意味着什么?”
fgets
更安全
现在,关于我删除的前导空间 当您使用
fgets
时,您将无法在输入前忽略空格
字符,因此我必须删除该空格,以使两个调用的结果几乎相同
我想我们不能真的说一种方法比另一种方法“更好”,只是fgets
更具可读性,可以确保您记住传递大小。这也可以通过将scanf
调用封装到正确构建格式字符串的输入读取函数中来实现。这还可以让您在阅读之前跳过前导的空格
字符
编辑 很明显,我的观点是,从安全角度来看(如“不在字符数组外写入”),这两种解决方案都是有效的,因为您可以限制在这两种方法上读取的字符数 我显示的代码纯粹是为了表明可以将其限制在一定的大小,而不是它们具有完全相同的效果。
正如Andrew Henle所说,
%*c
确实会丢弃一个输入字符,如果用户提供的字符超过了我们所说的读取长度。但话说回来,这不是我的重点,也不是问题所在。 我只是把它放在那里,让它更接近于
fgets
的功能,因为fgets
会从缓冲区中删除\n
,如果输入量不大于您试图读取的量
据我所知,这个问题问的是scanfvsfgets
,没有特别的意图。至少有一个问题没有被描述 当然有很多额外的事情需要考虑,这取决于应用程序需要做什么,当然。
fgets的一些注意事项
:
- 如果你的意见
char _x[7000]; char* y; while ( ! feof (_f) ) { fscanf(_f,"%[^\n]\n",_x); y=x; }
scanf(" %[^\n]",line); // Bad - no buffer overflow protection.
char buffer[100]; scanf(" %99[^\n]",line); // a little better
char buffer[100]; if (fgets(buffer, sizeof buffer, stdin)) { buffer[strcspn(buffer, "\n")] = '\0'; // Lop off potential tailing \n
char *line = NULL; size_t len = 0; ssize_t nread; while ((nread = getline(&line, &len, stdin)) != -1) {