2016-01-13 130 views
2

我真的停留在某種東西上。C fscanf返回錯誤的值

我有一個文本文件,其中有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」甚至不打印,浮點數字打印出來。

我在做什麼錯?

任何幫助將不勝感激。

謝謝。

+2

在printf(「%s \ n」,word)中使用'word'前檢查'fscanf(fp,「%s」,word)== 1「的結果值;' – chux

+0

我們可以看到類型單詞a和j的聲明? –

+3

請參閱['while(!feof(file))'總是錯誤](http://stackoverflow.com/questions/5431941/while-feof-file-is-always-wrong)獲取有關爲什麼您的外部循環爲錯誤。你需要測試'fscanf()'的結果 - 而不是或者'feof()'的結果,或者測試'fscanf()'的結果通常就足夠了。 –

回答

6

按照標準:

的輸入項被定義爲不超過任何指定的字段寬度和其是,或爲一個前綴,一個匹配的輸入序列的輸入字符的最長序列。

可能的原因是nine是給你ne是因爲,讀取double值時,nan是一個可接受的值。因此,ni被讀取以確定它是而不是nan

同樣,用in這個詞,表示inf的有效前綴表示無窮大。

該標準還規定在腳註:

的fscanf推至多一個輸入字符回到的輸入流。

所以很有可能這就是爲什麼nine中的i未被推回。

底線是,當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作爲雙將實際工作 - 這是圖書館的預期行爲(以及如何你原來的代碼會工作要不是有問題)。如果這是不可接受的,你可以做一些事情,比如在之前嘗試將它作爲一個雙精度來評估字符串,以確保它不是那些特殊值之一。

+0

非常感謝!我使用sscanf方法並打印所有單詞。再次感謝! –

+0

這個解決方案並不完全令人滿意:以'inf'開頭的行應該被解析爲一個數字而不是一個字符串。文件格式需要更精確地指定。 – chqrlie

+0

@chqrlie,我可以理解這個評論,如果它*被指定爲'inf'應該被當作一個字符串來處理,但是現在按照原來的方式工作(其中'inf'將被作爲一個浮點值來掃描),而且OP接受了答案,我不得不不同意。不過,我會記下它以確保沒有人被這種行爲所困擾。 – paxdiablo