2015-02-12 24 views
1

我有一個文件data.csv包含float類型的數據:與fgets不讀完整線用C


0.22,0.33,0.44

0.222,0.333,0.444


我需要將此文件讀入二維動態數組。但我無法閱讀fgets的全文。不知道爲什麼?

這裏是我的C代碼,我在Ubuntu使用:

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

int main(int argc, char *argv[]) { 
    FILE *fp; 
    float **data;  
    int i,j,rows=2,cols=3; 
    char * token; 
    fp=fopen("data.csv","r"); 
    if(fp==NULL) { 
      fprintf(stderr,"Can't open input file"); 
      exit(1); 
    } 

    data= malloc(rows * sizeof(float*)); 
    char *rowbuffer=malloc(cols * (sizeof(float)+sizeof(char))); 
    i=0; 
    while(fgets(rowbuffer,sizeof(rowbuffer),fp) !=NULL) {  
     data[i] = malloc(cols * sizeof(float));  
     j=0; 
     printf("\n %s",rowbuffer); 
     for (token = strtok(rowbuffer,","); token != NULL; token = strtok(NULL, ",")) { 
      data[i][j++] = atof(token); 
      /*printf("%s",token);*/ 
     } 
     i++; 
    } 
    free(rowbuffer); 
    for(i = 0; i < rows; i++) 
     free(data[i]); 
    free(data); 
    fclose(fp); 
} 

的輸出是這樣的:

0.22,0。

33,0.44

0.222,0

錯誤'./test「:雙重釋放或腐敗(出):0x0000000000adf270

Aborted(核心轉儲)

任何人都可以告訴爲什麼這個錯誤? :( 還是有更好的方式來讀取這種數據文件的

+2

'sizeof(rowbuffer)== sizeof(char *)'...這可能是4或8,具體取決於硬件。由於您假設*這是分配緩衝區的大小,因此您的假設是錯誤的。 – DevSolar 2015-02-12 08:48:00

+1

可能重複的[如何找到'sizeof'(指向數組的指針)?](http://stackoverflow.com/questions/492384/how-to-find-the-sizeofa-pointer-pointing-to -an-array) – 2015-02-12 08:48:24

+1

另外,縮進。空白空間是免費的。 ;-) – DevSolar 2015-02-12 08:53:48

回答

2

編碼問題是:

fgets(rowbuffer,sizeof(rowbuffer),fp) 

sizeof(rowbuffer)會給你只有指針的大小,而不是大小分配給指針的內存。

要解決此問題,需要分配的內存[cols * (sizeof(float)+sizeof(char)]的正確尺寸提供給fgets()

邏輯問題是:

您假設,因爲它需要對一個float變量的float值的印刷represntation將採取相同的內存量。不,這不是事實。在打印的表示中,每個數字(包括小數點以及小數點後的任何前導或尾隨0)都將消耗一個字節的內存。在爲目標緩衝區分配內存時應牢記這一點。

+0

但是,然後,分配的內存大小看起來是錯誤的預期用法。 – SukkoPera 2015-02-12 09:04:31

+1

@SukkoPera你就是。正在更新我的答案。 :-) – 2015-02-12 09:07:50

4

的一個問題是在這裏:

char *rowbuffer=malloc(cols * (sizeof(float)+sizeof(char))); 

sizeof(float)是的浮標使用存儲器,而不是它的文本表示大小。從文件讀取時,應該分配一個緩衝區以包含文本格式爲的整行。在你的情況是良好的選擇可能是以下幾點:

int bufsize = cols * (3 + DBL_MANT_DIG - DBL_MIN_EXP + 1) + 1; 

(爲什麼該值看到這一點,你需要#include什麼:What is the maximum length in chars needed to represent any double value?尾隨+ 1是佔換行符,這fgets()不讀,包括在緩衝區中。)

但是,假定輸入文件中沒有格式錯誤,所以您可能需要爲該值添加一些額外的鬆弛。

一旦你的價值,用它在兩個malloc()fgets()

char *rowbuffer=malloc(bufsize); 
i=0; 
while(fgets(rowbuffer,bufsize,fp) !=NULL) { 
... 

在一個側面說明,輸入文件看起來像它可以更好地利用scanf()讀取。

+0

感謝您的意見。我認爲使用'bufsize'這種方式保留的內存將比實際使用的多得多。關於我的csv文件的兩件事是,我沒有關於它有多少行和列的先前信息 - 也可以是數千或更多。其次,用於各個值的精度可以變化,例如0.124或可以是0.001204。 – Kaur 2015-02-14 05:43:41

+0

@Kaur:嗯,這很大程度上取決於您想要讀取的文件中的數據組織方式。如果行數是幾十個字符(假設爲80-100),這是我對你的情況所假設的,使用行緩衝區通常是可以負擔得起的,讀完後你甚至不需要它。如果行數可能會(更長),並且/或者如果您不知道最大長度,那麼您將不得不採用允許您一次讀取一個值的不同方法,例如'scanf()'方法我在暗示。你有看看嗎? – SukkoPera 2015-02-16 08:27:07

+0

@Kaur:關於不同的精度,你有沒有看看我給你的鏈接? – SukkoPera 2015-02-16 08:27:41