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()
更好地读取。
我有一个文件 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()
更好地读取。