在实用C编程一书中,我发现fgets()
和sscanf()
的组合用于读取输入。但是,在我看来,仅使用fscanf()
函数可以更轻松地实现相同的目标:
从书中(想法,而不是例子):
int main()
{
int age, weight;
printf("Enter age and weight: ");
char line[20];
fgets(line, sizeof(line), stdin);
sscanf(line, "%d %d", &age, &weight);
printf("\nYou entered: %d %d\n", age, weight);
return 0;
}
我认为应该如何:
int main()
{
int age, weight;
printf("Enter age and weight: ");
fscanf(stdin, "%d %d", &age, &weight);
printf("\nYou entered: %d %d\n", age, weight);
return 0;
}
或者我有一些隐藏的怪癖?
答案 0 :(得分:10)
这两种方法存在一些行为差异。如果您使用fgets()
+ sscanf()
,则必须在同一行输入两个值,而fscanf()
上的stdin
(或等效地,scanf()
)会读取它们如果在您输入的第一行找不到第二个值,则关闭不同的行。
但是,最重要的差异可能与处理错误情况以及面向行的输入和面向字段的输入的混合有关。
如果您阅读了使用sscanf()
阅读后无法使用fgets()
解析的行,则您的程序可以简单地丢弃该行并继续前进。但是,fscanf()
,当它无法转换字段时,会在流上留下所有输入。因此,如果您未能阅读所需的输入,则必须自己阅读所有想要忽略的数据。
如果您想在代码中混合使用面向字段(ala scanf()
)和面向行(例如fgets()
)调用,则会出现另一个微妙的问题。例如,当scanf()
转换int
时,它会在输入流上留下\n
(假设有一个,例如按下回车键),这将导致后续调用到fgets()
只返回输入中的那个字符。对于新程序员来说,这是一个非常普遍的问题。
所以,虽然你是对的,你可以这样使用fscanf()
,但使用fgets()
+ sscanf()
可以避免一些麻烦。
答案 1 :(得分:4)
仅使用fscanf()
的问题主要是在错误管理中。
想象一下,你向两个节目输入了“ 51岁,85公斤”。
sscanf()
中的第一个程序失败,你仍然有line
向用户报告错误,尝试不同的解析选择,某事;
第二个程序在年失败,age
可用,weight
无法使用。
请记住始终检查*scanf()
的返回值以进行错误检查。
fgets(line, sizeof(line), stdin);
if (sscanf(line, "%d%d", &age, &weight) != 2) /* error with input */;
修改
使用第一个程序,错误发生后,输入缓冲区清零;使用第二个程序,输入缓冲区以YEAR ...
开始第一种情况下的恢复很容易;第二种情况下的恢复必须通过某种方式清除输入缓冲区。
答案 2 :(得分:1)
fscanf()
与fgets()
/ sscanf()
之间没有区别:
发生两种类型的错误:I / O和格式。
fscanf()
同时在一个函数中处理这两种错误类型,但提供的恢复选项很少。单独的fgets()
和sscanf()
允许I / O问题与格式问题逻辑分离,从而更好地恢复。
从扫描中分离I / O允许多个
sscanf()
选项。如果给定的缓冲区扫描没有实现所需的结果,则可以使用具有不同格式的其他sscanf()
。
'\0'
。
'\0'
很少发生,但如果发生sscanf()
,fscanf()
将无法看到它,因为扫描因其出现而停止,而{{1}}仍在继续。
在所有情况下,检查所有三个功能的结果。