【问题标题】:infinite loop fscanf string textfile c programming无限循环 fscanf 字符串文本文件 c 编程
【发布时间】:2013-09-20 04:46:17
【问题描述】:

为什么当我扫描文本文件中的字符串时,它总是进入无限循环?

while(val = fscanf(stdin,"%lf%c",d,c) != EOF)
{if(val==0){//error}
else if(c='\n'){//error print char}
else{//print double}
}

文本文件:

4.5
r5
23
s

我想要的是打印所有内容,但当我到达字符串时它总是给我一个无限循环。

【问题讨论】:

    标签: c string infinite-loop scanf


    【解决方案1】:

    scanf() 系列函数是一种折磨测试,不应该对新手程序员施加。它们非常难以准确使用。

    分析

    即使忽略代码布局(完全令人震惊——这是专业评估)并假设您有这样的变量声明:

    double  value;
    double *d = &value;
    char    newline;
    char   *c = &newline;
    int     val;
    

    而不是更合理的:

    double d;
    char   c;
    int    val;
    

    你的片段有大量的问题塞进几行。

    while(val = fscanf(stdin,"%lf%c",d,c) != EOF)
    {if(val==0){//error}
    else if(c='\n'){//error print char}
    else{//print double}
    }
    

    您已将比较结果分配给val,而不是将fscanf() 的返回值分配给val 并将其与EOF 进行比较。

    while ((val = fscanf(stdin, "%lf%c", d, c)) != EOF)
    

    现在代码只是错误的; fscanf() 可以返回 EOF(通常,但不保证是 -1),或 0,或 12,其中只有 2 是您正在寻找的答案.所以,循环条件应该是:

    while ((val = fscanf(stdin, "%lf%c", d, c)) == 2)
    

    或者,如果你有更简单的定义,那么它应该是:

    while ((val = fscanf(stdin, "%lf%c", &d, &c)) == 2)
    

    现在您知道读取了两个值。循环内的if (val == 0) 检查现在是多余的;只有在val == 2 时才进入循环体。

    您可以检查*c 中的值是否是换行符进行比较而不是赋值:

        if (*c == '\n')
    

    (或if (c == '\n');假设您有更简单的声明并忘记了原始代码中的& 字符。)但是,如果c 不是换行符,则它是一个错误,所以实际上它应该是一个!= 测试。

    while ((val = fscanf(stdin, "%lf%c", &d, &c)) == 2)
    {
        if (c != '\n')
            ...print error...
        else
            printf("Number = %g\n", d);
    }
    

    循环之后,您可以测试val == EOF vs val == 0 vs val == 1。第一个意味着您已达到 EOF 或发生错误;第二个表示输入中的下一个字符既不是空格也不是有效数字的一部分(例如,.+- 以外的字母或标点符号)。 val == 1 案例是深奥的;它要求文件的结尾出现在后面没有换行符(或任何其他字符)的数字之后。

    无限循环

    顺便说一句,导致无限循环的最可能原因是输入中的无效(非数字、非空白)字符。而且,经过仔细检查,我发现输入的第二行有一个r;这将触发您的代码的无限循环。 fscanf() 将始终返回 0,这不是 EOF,因此循环继续。 (它无法读取r%c,因为它必须先成功读取一个数字。)

    合成

    %lf 格式将跳过任何前导空格,包括换行符,因此您的代码试图确保每行有一个数字,并且没有尾随空格。在这种情况下,您可能会更好地使用fgets()strtod(),尽管完全正确地使用strtod() 并非完全无关紧要。以下代码忽略了strtod() 的细节。

    char line[4096];
    double d;
    
    while (fgets(line, sizeof(line), stdin) != 0)
    {
        char *end;
        d = strtod(line, &end);
        if (end == line || *end != '\n')
            ...incorrect format...
        else
            printf("Number = %g\n", d);
    }
    

    fgets() 返回空指针的唯一原因是您已达到 EOF 或发生错误。您可能希望在调用 strtod() 之前设置 errno = 0;,然后检查其值以发现超出范围的数字。

    【讨论】:

    • 现在我真的不需要高级编码,因为我是新手,但我真的只需要 fscanf。现在的问题是,当我从您的代码中说 == 2 时,我无法获取字符串,当我到达一个字母时它会停止我如何仅使用 fscanf "while ((val = fscanf(stdin, " %lf%c", &d, &c)) == 2"
    • 您无法通过调用fscanf() 来解决问题——这就是为什么fscanf() 是一项如此糟糕的工作。如果一切顺利,那很好。当出现任何问题时,使用的工具就是错误的,这就是fgets()sscanf() 发挥作用的时候。如果您真的想尝试恢复,那么您将使用getc() 之类的东西来读取不能作为数字开头的字符(+-. 或数字, 我相信)。当然,这意味着你会读得太远(除非你只是读了一个字符然后再试一次),所以你还需要ungetc()
    【解决方案2】:

    代码进入无限循环,因为fscanf(stdin,"%lf%c",d,c) 尝试读取一个数字并找到一个字母:r5 中的r。在未能扫描任何内容时,它会返回 00 != EOF 为 true,并且 true 分配给 val。并且while (val) 重复。问题是r 没有被任何东西消耗,所以下一个`fscanf() 反复尝试,结果相同。

    推荐

    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
      result = sscanf(buffer, "%lf %c", &d, &c);
      if (result != 1) ; //handle error
    }
    

    【讨论】:

    • 嗯……为什么是!= 1? ……哦……我认为%c 之前的空格非常微妙,需要一些解释。这意味着您允许尾随空格或制表符,而原始代码则不允许。这并不完全是错误的,但可以说是规范的变化。
    【解决方案3】:

    一个问题是您不应该尝试扫描换行符。另一个问题是不等于运算符!=precedence 比赋值更高,这意味着val 是比较的结果。第三个错误是您没有提供将值读入的指针(导致未定义的行为)。

    我建议这样改:

    while (scanf("%lf", &d) == 1)
    {
        printf("You have read %f\n", d);
    }
    

    只要输入是浮点数,上面的循环就会循环。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-20
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 2015-06-22
      相关资源
      最近更新 更多