我真的被困在某事上。
我有一个文本文件,其中有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”这个词甚至没有打印,会打印一个浮点数。
我做错了什么?
非常感谢任何帮助。
感谢。
答案 0 :(得分:6)
按照标准:
输入项被定义为输入字符的最长序列,其不超过任何指定的字段宽度,并且是匹配输入序列的前缀,或者是匹配输入序列的前缀。
nine
给你ne
的可能原因是,在阅读双精度值时,nan
是可接受的值之一。因此,我会读取n
和i
以确定它不 nan
。
同样,使用单词in
,inf
的有效前缀代表无穷大。
该标准还在脚注中说明:
fscanf将 最多 一个输入字符推回到输入流中。
所以很有可能这就是为什么i
中nine
没有被推回的原因。
最重要的是,当fscanf
操作由于某种原因失败时,假设文件指针结束的位置基本上是不安全的。
解决此问题的一种方法是使用ftell
和fseek
为每个成功项目保存文件指针,以便您可以移动到正确的文件位置。重新尝试阅读是不成功。
让我们说你有输入文件:
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]
这基本上是所期望的。
您需要注意的一件事是,将inf
或nan
之类的内容扫描为double实际上会起作用 - 这是库的预期行为(以及原始代码的行为方式)如果工作没有问题)。如果这是不可接受的,你可以做一些事情,比如在尝试将其扫描为double之前评估字符串,以确保它不是那些特殊值之一。