fgets没有在C中读取完整的行

时间:2015-02-12 08:44:27

标签: c pointers readfile fgets coredump

我有一个文件data.csv,其中包含float类型数据:


  

0.22,0.33,0.44

     

0.222,0.333,0.444


我需要将此文件读入二维动态数组。但是我无法阅读fgets的全部内容。不确定为什么?

这是我在Ubuntu上使用的C代码:

#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

     

��

     

444

     

`./test'错误:双重免费或损坏(输出):0x0000000000adf270

     

中止(核心倾销)

任何人都可以告诉为什么会出现这个错误? :( 或者有更好的方法来阅读这种数据文件吗?

2 个答案:

答案 0 :(得分:4)

这里有一个问题:

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

sizeof(float)是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()更好地阅读。

答案 1 :(得分:2)

您的编码问题出在:

fgets(rowbuffer,sizeof(rowbuffer),fp)

sizeof(rowbuffer)将只给出指针的大小,而不是指定给指针的内存大小。

要解决此问题,您需要将已分配内存[cols * ( sizeof(float)+sizeof(char)]的正确大小提供给fgets()

逻辑问题出在:

您认为float值的打印的represntation 将占用与float变量相同的内存量。不,那不是真的。在打印的表示中,每个数字(包括小数点以及小数点后的任何前导或尾随0)将消耗每个字节一个字节。在为目标缓冲区分配内存时,应该记住这一点。