scanf
,同样也不应使用getline
。我开始迷茫:如果我遇到的每个输入函数都被人说不能使用,那我应该使用什么?有没有更“标准”的获取输入的方法我不知道的?
scanf
,同样也不应使用getline
。通常情况下,fgets()
被认为是一个不错的选择。它可以将整行读入缓冲区,然后你可以对其进行必要的操作。如果您想要类似于 scanf()
的行为,则可以将所读取的字符串传递给 sscanf()
。
这种方法的主要优点是,如果转换失败,很容易进行恢复,而使用 scanf()
则会在 stdin
上留下输入需要清空的情况。此外,您不会陷入将逐行输入与 scanf()
混合使用的陷阱中,在这种情况下,例如 \n
通常会被留在 stdin
上,往往会导致新手编码人员误以为输入调用已被完全忽略。
以下示例可能会符合您的需求:
char line[256];
int i;
if (fgets(line, sizeof(line), stdin)) {
if (1 == sscanf(line, "%d", &i)) {
/* i can be safely used */
}
}
需要注意的是,fgets()
在遇到文件结尾或错误时返回NULL
,这就是为什么我用if
将其包裹的原因。而sscanf()
的调用结果表示成功转换的字段数量。
要记住,如果行的长度超过了缓冲区,fgets()
可能无法读取整行内容,在“严肃”程序中,这是您应该考虑的事情。
fflush(stdin)
在fgets()
之后如何?这样可以确保输入缓冲区过满(超过255个字符)不会影响对fgets()
的后续调用。 - Twonky对于可以设置输入长度限制的简单输入,我建议使用 fgets()
从终端读取数据。
这是因为 fgets()
允许您指定缓冲区大小(相比之下,gets()
几乎不应该用于从人类读取输入,原因就在于这一点):
char line[256];
if(fgets(line, sizeof line, stdin) != NULL)
{
/* Now inspect and further parse the string in line. */
}
记住它将保留例如换行符等特殊字符,这可能会令人惊讶。getline()
。对于 POSIX 代码而言,这可能是最佳的通用解决方案,因为它没有对要读取的行长度进行任何静态限制。getline
函数更加灵活。 - Fred Foo使用scanf
存在以下几个问题:
使用普通的%s
格式符读取文本与使用gets()
函数一样存在风险,如果用户输入的字符串长度超过目标缓冲区大小,会导致缓冲区溢出;
如果使用%d
或%f
格式符读取数字输入,则无法完全捕获和拒绝某些不良输入格式 -- 如果使用%d
读取整数,而用户输入"12r4
",scanf
会将12
转换并分配,而将r4
留在输入流中,从而破坏下一个读取操作;
某些格式符跳过前导空格,而另一些则不跳过,如忽略这一点可能会导致一些输入被完全跳过;
基本上,使用scanf
来保证输入的鲁棒性需要非常大的额外努力。
一个好的替代方案是使用fgets()
读取所有输入作为文本,然后使用sscanf
,或结合使用strtok
、strtol
、strtod
等函数来标记并转换输入。
fgets
获取数据,并使用sscanf
(或其他方法)解释它们。请参考此页面,了解为什么使用fgets
+sscanf
比使用scanf
更好。http://c-faq.com/stdio/scanfprobs.html
scanf
,并检查其返回值。 - asaelrscanf
是获取格式化输入的标准方法,而fgets
/fgetc
则是推荐的用于获取整行或单个字符的标准函数。大多数其他函数要么是非标准的,要么是特定于平台的。 - Some programmer dudegetline
函数。如果你的平台没有它,你可以用fgets
和malloc
来实现它。 - Fred Foo