哪个是从C中获取用户输入的最佳方式?

时间:2012-02-14 14:03:25

标签: c user-input

许多人说scanf不应该用于更严肃的程序",与getline相同。

我开始迷失方向:如果我遇到的每个输入功能都表示我不应该使用其中任何一个,那么我应该使用什么?是否有更多的标准"获得我不知道的输入的方式?

4 个答案:

答案 0 :(得分:35)

通常,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()在EOF或错误上返回NULL,这就是我将其包裹在if中的原因。 sscanf()调用返回已成功转换的字段数。

请记住,如果该行大于您的缓冲区,则fgets()可能无法读取整行,而在“严肃”程序中肯定是您应该考虑的。

答案 1 :(得分:11)

对于可以在输入长度上设置固定限制的简单输入,我建议您使用fgets()从终端读取数据。

这是因为fgets()允许你指定缓冲区大小(而不是gets(),因为这个原因应该从不用于读取人类的输入):

char line[256];

if(fgets(line, sizeof line, stdin) != NULL)
{
  /* Now inspect and further parse the string in line. */
}

请记住它会保留,例如换行符可能会令人惊讶。

更新:正如评论中所指出的,如果您对跟踪内存负责,可以选择更好的替代方案:getline()。这可能是POSIX代码的最佳通用解决方案,因为它对要读取的行的长度没有任何静态限制。

答案 2 :(得分:5)

使用scanf时存在几个问题:

  • 使用普通%s转化说明符阅读文字与使用gets()具有相同的风险;如果用户输入的字符串长度超过目标缓冲区的大小,则会出现缓冲区溢出;

  • 如果使用%d%f来读取数字输入,则无法捕获并完全拒绝某些错误模式 - 如果您正在读取带%d的整数并且用户类型“12r4”,scanf将转换并分配12,同时在输入流中留下r4以填充下一个读取内容;

  • 某些转化说明符会跳过前导空格,而其他转换说明符则不会,并且未将其考虑在内会导致出现完全跳过某些输入的问题;

基本上,使用scanf进行防弹读取需要额外的批次

一个不错的选择是使用fgets()将所有输入作为文本读取,然后使用sscanfstrtokstrtol,{{的组合来对输入进行标记和转换1}}等等。

答案 3 :(得分:2)

使用fgets获取数据并使用sscanf(或其他方法)来解释数据。

请参阅此页,了解为何最好使用fgets + sscanf而不是scanf

http://c-faq.com/stdio/scanfprobs.html