C fscanf返回错误的值

时间:2016-01-13 03:19:38

标签: c

我真的被困在某事上。

我有一个文本文件,其中有1个单词后跟~100个浮点数。浮点数由空格,制表符或换行符分隔。此格式在整个文本文件中重复多次。

例如,这就是文本文件的样子:

one 0.00591 0.07272 -0.78274 ... 
0.0673 ...
0.0897 ...
two 0.0654 ...
0.07843 ...
0.0873 ...
three ...
...
...

这是我的代码片段:

char word[30];
double a[1000];
double j;

while (!feof(fp))
    {
        fscanf(fp, "%s", word);
        printf("%s\n", word);
        while (!feof(fp) && (fscanf(fp, " %lf", &j)) == 1)
        {
            a[z] = j;
            z++;
            num_of_vectors++;
        }
        z = 0;
    }

文本文件中的“九”字样打印为“ne”。 并且“in”这个词甚至没有打印,会打印一个浮点数。

我做错了什么?

非常感谢任何帮助。

感谢。

1 个答案:

答案 0 :(得分:6)

按照标准:

  

输入项被定义为输入字符的最长序列,其不超过任何指定的字段宽度,并且是匹配输入序列的前缀,或者是匹配输入序列的前缀。

nine给你ne的可能原因是,在阅读双精度值时,nan是可接受的值之一。因此,我会读取ni以确定它 nan

同样,使用单词ininf的有效前缀代表无穷大。

该标准还在脚注中说明:

  

fscanf将 最多 一个输入字符推回到输入流中。

所以很有可能这就是为什么inine没有被推回的原因。

最重要的是,当fscanf操作由于某种原因失败时,假设文件指针结束的位置基本上是不安全的。

解决此问题的一种方法是使用ftellfseek为每个成功项目保存文件指针,以便您可以移动到正确的文件位置。重新尝试阅读是成功。

让我们说你有输入文件:

one 1 2 3 4 5
nine 9 8 7 6 5
in 3.14159 2.71828

以下代码将保存并恢复文件位置,使其按您的意愿工作:

#include <stdio.h>

int main(void) {
    char buff[50]; double dbl; size_t pos;
    FILE *fin = fopen("inputFile.txt", "r");
    while (fscanf(fin, "%s", buff) == 1) {
        printf("Got string [%s]\n", buff);
        pos = ftell(fin);
        while (sscanf(buff, "%lf", &dbl) == 1) {
            printf("Got double [%f]\n", dbl);
            pos = ftell(fin);
        }
        fseek(fin, pos, SEEK_SET);
    }
    fclose(fin);
    return 0;
}

通过评论 fseek,您可以看到与您描述的内容类似的行为:

Got string [one]
Got double [1.000000]
Got double [2.000000]
Got double [3.000000]
Got double [4.000000]
Got double [5.000000]
Got string [ne]
Got double [9.000000]
Got double [8.000000]
Got double [7.000000]
Got double [6.000000]
Got double [5.000000]
Got double [3.141590]
Got double [2.718280]

我认为这个解决方案有点混乱,因为它不断调用ftell并偶尔调用fseek来使其工作。

另一种方法是将所有作为字符串读取,并在读取之后决定它是数字还是带有sscanf操作的字符串,如下面的代码所示(带有上述输入文件):

#include <stdio.h>

int main(void) {
    char buff[50]; double dbl;
    FILE *fin = fopen("inputFile.txt", "r");
    while (fscanf(fin, "%s", buff) == 1) {
        if (sscanf(buff, "%lf", &dbl) == 1) {
            printf("Got double [%f]\n", dbl);
        } else {
            printf("Got string [%s]\n", buff);
        }
    }
    fclose(fin);
    return 0;
}

这是有效的,因为浮点值实际上是字符串的正确子集(即,它没有嵌入的空格)。

上述两个程序的输出是:

Got string [one]
Got double [1.000000]
Got double [2.000000]
Got double [3.000000]
Got double [4.000000]
Got double [5.000000]
Got string [nine]
Got double [9.000000]
Got double [8.000000]
Got double [7.000000]
Got double [6.000000]
Got double [5.000000]
Got string [in]
Got double [3.141590]
Got double [2.718280]

这基本上是所期望的。

您需要注意的一件事是,将infnan之类的内容扫描为double实际上会起作用 - 这是库的预期行为(以及原始代码的行为方式)如果工作没有问题)。如果这是不可接受的,你可以做一些事情,比如在尝试将其扫描为double之前评估字符串,以确保它不是那些特殊值之一。