![](/img/trans.png)
[英]Is there any reason to use scanf or fscanf over fgets+sscanf
[英]Using fscanf() vs. fgets() and sscanf()
在《实用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;
}
还是我缺少一些隐藏的怪癖?
两种方法之间存在一些行为差异。 如果使用fgets()
+ sscanf()
,则必须在同一行上输入两个值,而如果stdin
(或等效的scanf()
)上的fscanf()
找不到第二个值,则会从不同的行读取它们在您输入的第一行。
但是,最重要的差异可能与处理错误情况以及行输入和场输入的混合有关。
如果您在使用fgets()
读取一行后读取了无法用sscanf()
解析的行,则程序可以简单地放弃该行并继续前进。 但是, fscanf()
无法转换字段时,会将所有输入保留在流中。 因此,如果您无法读取所需的输入,则必须去读取所有要忽略的数据。
如果要在代码中混合面向字段的调用(ala scanf()
)和面向行的调用(例如fgets()
),则会出现另一个细微的陷阱。 例如,当scanf()
转换一个int
,它将在输入流上留下一个\\n
(假设有一个,例如,按回车键),这将导致对fgets()
的后续调用仅返回输入中的那个字符。 对于新程序员来说,这确实是一个普遍的问题。
因此,虽然可以使用fscanf()
这样正确,但通过使用fgets()
+ sscanf()
可以避免一些麻烦。
仅使用fscanf()
的问题主要是在错误管理中。
假设您在两个程序中都输入了“ 51年,85 Kg ”。
第一个程序在sscanf()
失败,并且您仍然可以通过该line
向用户报告错误,尝试对某事物进行不同的解析选择;
第二个程序在几年后失败, age
可用, weight
不可用。
请务必始终检查*scanf()
的返回值以进行错误检查。
fgets(line, sizeof(line), stdin);
if (sscanf(line, "%d%d", &age, &weight) != 2) /* error with input */;
编辑
对于第一个程序,在错误之后,输入缓冲区被清除; 在第二个程序中,输入缓冲区以YEAR开头。
在第一种情况下,恢复很容易; 在第二种情况下,恢复必须经过某种清除输入缓冲区的过程。
在以下情况下, fscanf()
与fgets()
/ sscanf()
之间没有区别:
发生两种类型的错误:I / O和格式。
fscanf()
在一个函数中同时处理这两种错误类型,但提供的恢复选项很少。 分开的fgets()
和sscanf()
允许将I / O问题与格式问题进行逻辑分离,从而实现更好的恢复。
将I / O与扫描
sscanf()
可以使用多个sscanf()
选项。 如果给定的缓冲区扫描无法实现所需的结果,则可以使用其他具有不同格式的sscanf()
。
'\\0'
。 很少发生
'\\0'
,但是如果发生一次,则sscanf()
不会看到它,因为扫描随着发生而停止,而fscanf()
继续。
在所有情况下,请检查所有三个功能的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.