fgets 不读取 C 中的完整行

fgets not reading complete line in C

我有一个文件 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

Error in `./test': double free or corruption (out): 0x0000000000adf270

Aborted (core dumped)

谁能告诉我为什么会出现这个错误? :( 或者有没有更好的方法读取这种数据文件?

您的编码问题在:

fgets(rowbuffer,sizeof(rowbuffer),fp)

sizeof(rowbuffer)只会给你指针的大小,而不是分配给指针的内存大小。

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

你的符合逻辑的问题在:

您假定 打印表示 float 值将占用与 float 变量相同的内存量。不,那不是真的。在印刷表示中,每个数字(包括小数点和小数点后的任何前导或尾随0)将各自占用一个字节的内存。在为目标缓冲区分配内存时应牢记这一点。

这里有一个问题:

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() 更好地读取。