使用fscanf从.txt文件读取数据到C动态数组时触发Access Violation错误
问题分析与修复步骤
1. 打印循环的数组越界
你在初始化数组后添加的打印循环中,列循环条件错误:每个天体的位置只有3个分量(x/y/z),但你使用column < numberOfBodies作为循环条件,当numberOfBodies大于3时,会访问超出每行分配的内存范围,触发未定义行为。
修复:将列循环条件改为column < 3:
for (row = 0; row < numberOfBodies; row++) { for (column = 0; column < 3; column++) // 改为3,对应x/y/z三个分量 { printf(" %lf", initialPositions[row][column]); } printf("\n"); }
2. 读取文件时的索引初始化错误
打开文件前,前面的循环已经把row和column的值修改到了numberOfBodies(比如numberOfBodies=5时,row=5,column=5)。此时用这个row值访问initialPositions[row],已经超出了数组的行范围(数组行索引是0到numberOfBodies-1),直接导致Access Violation。
修复:在读取文件前重新初始化row为0,同时直接用固定索引0/1/2访问列,避免依赖column变量:
// 打开文件后,重置row为0 row = 0; while (fscanf(file, "%lf %lf %lf", &initialPositions[row][0], &initialPositions[row][1], &initialPositions[row][2]) != EOF) { printf("%lf %lf %lf\n", initialPositions[row][0], initialPositions[row][1], initialPositions[row][2]); row++; // 防止读取超过numberOfBodies行,避免越界 if (row >= numberOfBodies) break; }
3. 跳过文件的表头行
文件第一行是文本表头pos_x, pos_y, pos_z,fscanf无法将其解析为double,会导致读取失败,后续循环逻辑混乱。
修复:用fgets跳过第一行:
FILE *file = fopen("initial_positions.txt", "r"); if (file == NULL) { printf("\nUnable to access the 'initial_positions.txt' file.\n"); exit(1); } else { char buffer[256]; // 跳过第一行表头 fgets(buffer, sizeof(buffer), file); row = 0; // 重置row为0 // ... 读取逻辑 }
4. 不要返回已释放的内存
你在函数末尾调用了free(initialPositions),然后返回这个指针,此时返回的是已经被释放的悬空指针,调用者使用它会触发未定义行为。
修复:移除free(initialPositions),把内存释放的责任交给调用者:
// free(initialPositions); // 删除这行 return initialPositions;
同时在main函数中调用完后记得释放内存:
int main() { int numberOfBodies = 5; double **positions = ReadInitialPositions(numberOfBodies); // 使用positions的逻辑... // 释放内存 for (int i = 0; i < numberOfBodies; i++) { free(positions[i]); } free(positions); return 0; }
5. 内存分配的错误检查
malloc可能返回NULL(内存不足时),不检查会直接崩溃。
修复:添加malloc返回值检查,同时在分配失败时释放已分配的内存,避免泄漏:
double **initialPositions = malloc(sizeof(double*) * numberOfBodies); if (initialPositions == NULL) { printf("Failed to allocate memory for rows.\n"); exit(1); } for (row = 0; row < numberOfBodies; row++) { initialPositions[row] = malloc(sizeof(double) * 3); if (initialPositions[row] == NULL) { printf("Failed to allocate memory for row %d.\n", row); // 释放已分配的内存 for (int i = 0; i < row; i++) { free(initialPositions[i]); } free(initialPositions); exit(1); } }
修复后的完整代码
#include <stdio.h> #include <stdlib.h> double **ReadInitialPositions(int numberOfBodies) { int row = 0; int column = 0; double **initialPositions = malloc(sizeof(double*) * numberOfBodies); if (initialPositions == NULL) { printf("Failed to allocate memory for rows.\n"); exit(1); } for (row = 0; row < numberOfBodies; row++) { initialPositions[row] = malloc(sizeof(double) * 3); if (initialPositions[row] == NULL) { printf("Failed to allocate memory for row %d.\n", row); for (int i = 0; i < row; i++) { free(initialPositions[i]); } free(initialPositions); exit(1); } } // 初始化后打印(可选,用于验证) for (row = 0; row < numberOfBodies; row++) { for (column = 0; column < 3; column++) { printf(" %lf", initialPositions[row][column]); } printf("\n"); } FILE *file = fopen("initial_positions.txt", "r"); if (file == NULL) { printf("\nUnable to access the 'initial_positions.txt' file.\n"); // 释放已分配内存 for (int i = 0; i < numberOfBodies; i++) { free(initialPositions[i]); } free(initialPositions); exit(1); } else { char buffer[256]; // 跳过表头行 fgets(buffer, sizeof(buffer), file); row = 0; while (fscanf(file, "%lf %lf %lf", &initialPositions[row][0], &initialPositions[row][1], &initialPositions[row][2]) != EOF) { printf("%lf %lf %lf\n", initialPositions[row][0], initialPositions[row][1], initialPositions[row][2]); row++; if (row >= numberOfBodies) { break; } } } fclose(file); return initialPositions; } int main() { int numberOfBodies = 5; double **positions = ReadInitialPositions(numberOfBodies); // 这里可以添加使用positions的逻辑 // 释放内存 for (int i = 0; i < numberOfBodies; i++) { free(positions[i]); } free(positions); return 0; }
内容的提问来源于stack exchange,提问作者user11080418

