2015-02-12 58 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