C语言读取txt文件到double数组时数值不符的问题排查
问题:读取文本文件数值到double数组时数值不符且input[i]触发段错误
我想把txt文件里的一列数值读到C语言的double数组里(多年没写C/C++,完全是新手状态)。现在读取后数组里的数值和文件里的对不上,不知道原因和解决办法。已经在CMAKE里把C标准设为C99,因为代码库其他部分是2006年的旧代码,不过这些部分要等数值正确读取后才会运行。
实现代码
#include <stdio.h> #include <stdlib.h> int main(){ double *input = malloc(sizeof(double) * 30); FILE *fReader= fopen("../values.txt", "r"); if (fReader == NULL){ perror("following error occurred:"); return EXIT_FAILURE; } for(int i=0; i<30; i++){ // 如果用input[i]会触发段错误 if(fscanf(fReader, "%f", (input+i)) != 1){ perror("following error occurred during value reading: "); fclose(fReader); return EXIT_FAILURE; } printf( "current value is %e\n", *(input+i)); } if (ferror(fReader)){ perror("following error occurred after reading: "); return EXIT_FAILURE; } if (fclose(fReader)){ perror("following error occurred closing file: "); return EXIT_FAILURE; } return 0; }
注:使用input[i]会触发段错误。这段代码能运行,但数组里的数值和文件里的不一致。
GDB调试输出
$1 = { { 5.2090851696161347e-315, 1.5708573496820653e-314, 5.1267133989091838e-315, 0, 1.5717337030679671e-314, 5.1214795787184985e-315, 1.5632763856615201e-314, 1.5698868046570466e-314, 5.1603745953073066e-315, 1.5776507290912971e-314, 5.1890476209538565e-315, 1.5757154067636091e-314, 5.1701259393153366e-315, 1.5646987621187767e-314, 1.5706057487281833e-314, 1.5745646547527293e-314, 5.074800315787295e-315, 1.5708606090331309e-314, 1.5584251847289437e-314, 5.0712624352138373e-315, 1.5742053425473973e-314, 5.121533268832232e-315, 1.5713904213165801e-314, 1.5767611663662882e-314, 5.1426528410215284e-315, 1.5729652822422439e-314, 5.1593853918931727e-315, 1.5747322610883588e-314, 4.9742190195450526e-315, 5.0023562211173747e-315 } }
values.txt文件内容
0.421499729344799 -0.0637534886782198 0.106157122495887 0 -0.0769690171367188 0.0982644454758486 -0.0186078658644284 -0.0558087634241033 0.188837376753259 -0.207397239912854 0.300632085420638 -0.149027358129317 0.218247717844644 -0.0239702769714967 -0.0612296530370315 -0.119660179409031 0.0451857273951361 -0.0638026393400715 -0.00797183286147529 0.0425181372831318 -0.114241700013729 0.0983454129367622 -0.0717922840839158 -0.18056777523574 0.135388066712405 -0.0955414085415107 0.185853919257983 -0.122187706120336 0.00796167779508749 0.0132655904045542
解决办法
1. 数值不符的核心原因:格式符不匹配
你用了%f格式符读取double类型变量,但%f在fscanf里是给float类型用的。读取double必须用%lf格式符。
因为float和double的内存占用不同(通常float是4字节,double是8字节),用%f读取到double地址时,只会写入前4字节,剩下的4字节是垃圾值,导致最终看到的是极小的错误数值(比如你GDB里的那些接近0的极小值)。
修正后的fscanf语句应该是:
if(fscanf(fReader, "%lf", (input+i)) != 1)
2. input[i]触发段错误的原因
input[i]和*(input+i)是完全等价的写法,理论上不该出现段错误。出现问题大概率是因为你之前用%f写入时破坏了内存:
- 用
%f往double地址写float数据,相当于只写了一半的内存,后续写入可能覆盖malloc分配区域之外的内存,破坏了堆结构,导致访问input[i]时触发段错误。 - 先修正格式符为
%lf,再测试input[i],就不会有段错误了。
另外,建议在malloc后检查是否分配成功,避免空指针访问:
double *input = malloc(sizeof(double) * 30); if (input == NULL) { perror("malloc failed"); return EXIT_FAILURE; }
3. 额外的小问题:printf格式错误
你代码里的printf语句写了%current,这是笔误,应该去掉前面的%,改成:
printf( "current value is %e\n", *(input+i));
修正后的完整代码
#include <stdio.h> #include <stdlib.h> int main(){ double *input = malloc(sizeof(double) * 30); if (input == NULL) { perror("malloc failed"); return EXIT_FAILURE; } FILE *fReader= fopen("../values.txt", "r"); if (fReader == NULL){ perror("following error occurred:"); free(input); // 分配成功后要释放 return EXIT_FAILURE; } for(int i=0; i<30; i++){ if(fscanf(fReader, "%lf", &input[i]) != 1){ // 改用input[i]的地址 perror("following error occurred during value reading: "); fclose(fReader); free(input); return EXIT_FAILURE; } printf( "current value is %e\n", input[i]); } if (ferror(fReader)){ perror("following error occurred after reading: "); fclose(fReader); free(input); return EXIT_FAILURE; } if (fclose(fReader)){ perror("following error occurred closing file: "); free(input); return EXIT_FAILURE; } free(input); // 最后释放内存 return 0; }
内容的提问来源于stack exchange,提问作者stucash
相关产品推荐
相关产品推荐

