繁体   English   中英

使用fscanf()与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()之间没有区别:

  1. 输入数据格式正确。

发生两种类型的错误:I / O和格式。 fscanf()在一个函数中同时处理这两种错误类型,但提供的恢复选项很少。 分开的fgets()sscanf()允许将I / O问题与格式问题进行逻辑分离,从而实现更好的恢复。

  1. 只有1个解析路径。

将I / O与扫描sscanf()可以使用多个sscanf()选项。 如果给定的缓冲区扫描无法实现所需的结果,则可以使用其他具有不同格式的sscanf()

  1. 没有嵌入的'\\0'

很少发生'\\0' ,但是如果发生一次,则sscanf()不会看到它,因为扫描随着发生而停止,而fscanf()继续。

在所有情况下,请检查所有三个功能的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM