在C语言中,获取用户输入的最佳方式是什么?
在C语言中,从用户获取输入的最佳方法是什么?
对于简单的输入,可以设置输入长度的固定限制,我建议使用fgets()
从终端读取数据。这是因为fgets()
允许您指定缓冲区大小(与此相反,gets()
因为这个原因应该基本上永远不要用于从人类读取输入):
char line[256]; if(fgets(line, sizeof line, stdin) != NULL) { /* 现在检查并进一步解析line中的字符串。 */ }
请记住,它会保留换行符字符,这可能会让人感到惊讶。
更新:正如评论中指出的,如果您可以负责跟踪内存,那么有一个更好的选择:getline()
。这可能是POSIX代码的最佳通用解决方案,因为它对要读取的行的长度没有任何静态限制。
“可以设置输入长度的简单输入”听起来不像是“严肃”的程序。POSIX的getline
函数更加灵活。
如果我能为我的问题找到两个赢家,那么你会是第二个,因为你详细解释了getline()
的细节以及你解释的gets()
的行为。但是FatalError的答案对于如何使用这种技术有更多的细节。
在C语言中,从用户获取输入的最佳方法是什么?
使用scanf
存在以下几个问题:
- 使用纯粹的
%s
转换说明符读取文本时存在与使用gets()
相同的风险;如果用户输入的字符串长度超过目标缓冲区的大小,就会发生缓冲区溢出; - 如果使用
%d
或%f
来读取数值输入,无法完全捕获和拒绝某些错误模式——如果使用%d
读取整数,用户输入"12r4
",scanf
将转换并赋值为12
,而将r4
留在输入流中,干扰下一次读取; - 某些转换说明符跳过前导空格,而其他则不跳过,如果不考虑这一点,可能导致某些输入完全被跳过;
基本上,使用scanf
需要付出很多额外的努力来确保读取的安全性。
一个好的替代方法是使用fgets()
将所有输入作为文本读取,然后使用sscanf
或strtok
、strtol
、strtod
等组合对输入进行标记化和转换。
谢谢,现在我知道人们为什么说scanf
可能不好的原因了。
在C语言中,从用户获取输入有多种方法,其中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可以安全使用 */ } }
上述代码中需要注意的是,fgets()
在EOF或错误时返回NULL
,这就是为什么我将其包裹在if
中的原因。sscanf()
返回成功转换的字段数。
请记住,如果行的长度大于缓冲区大小,fgets()
可能无法读取整行,这在一个“严肃”的程序中是您应该考虑的。
那么,在fgets()
之后添加fflush(stdin)
以确保超过255个字符的输入缓冲区不会影响后续对fgets()
的调用呢?
fflush(stdin)
在C语言中是未定义的(尽管在某些平台上确实会执行您的建议)。但是是的,这样可以使其更加健壮。