C语言读写CSV文件触发0xC0000005访问违例错误排查
问题根因
读取时抛出0xC0000005: Access violation reading location错误由以下几个问题共同或单独导致,按触发概率从高到低排序:
- 数组索引越界
- 读写分隔逻辑不匹配:写入CSV时你用
\n作为每个整数的分隔,每个数单独占一行,读取时却按,作为分隔符调用strtok_s,格式不匹配会导致token解析不符合预期,计数变量w累加值和实际数据量不匹配。 - 无边界校验:给
Ay分配的内存长度是n * sizeof(int),但写入Ay[w]前没有判断w是否小于n,只要读到的数字数量超过数组分配长度,就会写入未申请的非法内存地址触发违例。 - 循环场景变量未重置:如果
w是全局变量或外层作用域变量,多次循环执行读写流程时w不会自动归零,第二次读取时w的初始值就是上一次读取的元素总数,直接从超出数组长度的索引位置写入,立刻触发违例。
- 读写分隔逻辑不匹配:写入CSV时你用
- 文件操作逻辑不严谨
- 写入逻辑中不管
fopen_s是否打开成功,都会无条件执行fclose(fpt1),如果文件打开失败,fpt1是空指针或野指针,fclose调用会直接破坏内存布局,导致后续内存访问异常。 - 写入时使用
"w+"模式(读写模式),没有必要,且如果写入时的count变量和读取时的n值不一致,比如写入元素数大于n,读取时分配的内存长度不足以存下所有数据,必然越界。
- 写入逻辑中不管
修复方案
按以下规则修改代码即可解决问题:
- 统一读写的分隔逻辑:如果保持每行存一个整数的写入格式,读取时直接把
fgets读到的每行内容转成整数即可,不需要调用strtok按逗号分割;如果要使用逗号分隔的标准CSV格式,写入时每个整数后补逗号,再对应修改读取的分隔符。 - 补全所有错误兜底:
fclose必须放在文件打开成功的分支内,禁止对空指针、野指针调用文件操作函数;内存分配、文件打开失败时直接走错误返回逻辑,不要继续执行后续代码。 - 加数组边界校验:写入数组前先判断索引
w是否小于数组长度n,超出长度直接停止读取,避免越界。 - 循环场景做好变量重置:每次进入读取逻辑前,把索引
w重置为0;如果每次循环n的数值会变化,先释放之前malloc的Ay内存,再重新分配对应长度的空间,避免内存泄漏和长度不匹配问题。 - 写入完成后确保内容落盘:文件写入结束后正常关闭文件句柄,再启动读取流程,避免读到残缺的文件内容。
修正后参考代码
写入部分
FILE* fpt1 = NULL; errno_t err3; err3 = fopen_s(&fpt1, "Ay.csv", "w"); if (err3 != 0) { // 自行补充打开失败的错误处理逻辑,比如打印错误码、返回错误 return; } for (int i = 0; i < count; i++) { // 保持每行一个整数的写入格式,和读取逻辑对齐 fprintf(fpt1, "%d\n", Ay[i]); } // 仅在文件打开成功时执行关闭 if (fpt1 != NULL) { fclose(fpt1); fpt1 = NULL; }
读取部分
// 循环调用场景下先释放之前分配的内存,避免内存泄漏 if (Ay != NULL) { free(Ay); Ay = NULL; } Ay = malloc(n * sizeof(int)); if (Ay == NULL) { // 自行补充内存分配失败的错误处理逻辑 return; } FILE* file = NULL; errno_t err; char line[20000]; int w = 0; // 每次读取前重置索引为0 err = fopen_s(&file, "Ay.csv", "r"); if (err != 0) { // 自行补充打开失败的错误处理逻辑 free(Ay); Ay = NULL; return; } while (fgets(line, sizeof(line), file)) { // 加边界校验,防止数组越界 if (w >= n) { break; } // 写入格式为每行一个数,直接转换整行内容即可 Ay[w] = atoi(line); w++; } // 仅在文件打开成功时执行关闭 if (file != NULL) { fclose(file); file = NULL; }
内容的提问来源于stack exchange,提问作者S2022
相关产品推荐
相关产品推荐

