读取简单CSV文件时触发Segmentation fault:11(C语言)
排查并修复CSV读取的段错误问题
你的段错误大概率是由几个常见的内存操作问题导致的,咱们一步步拆解分析:
1. 结构体数组越界访问
你的unused数组大小是MAX_USEABLE,但在readCSV的循环里,i一直递增却没有做边界检查。当CSV的行数超过MAX_USEABLE时,程序会写入到数组之外的内存区域,直接触发段错误。
2. 空指针传入strcpy
如果某一行CSV的列数不足2列(比如只有1列或者空行),getunused会返回NULL。这时候执行strcpy(unused[i].col1, NULL)会因为访问空指针导致段错误。
3. fgets缓冲区大小不匹配
你调用fgets(line, 1024, file),但line的定义是char line[MAX_LINE_LENGTH];。如果MAX_LINE_LENGTH小于1024,会导致缓冲区溢出,破坏栈上的其他数据,进而引发不可预测的错误(包括段错误)。
修复后的代码示例
针对这些问题,咱们修改代码如下:
#include <stdio.h> #include <string.h> #include <stdlib.h> // 假设这些宏已经提前定义 #define MAX_ARG_LENGTH 256 #define MAX_USEABLE 100 #define MAX_LINE_LENGTH 1024 #define FIRST_COLUMN 1 #define SECOND_COLUMN 2 struct unused_s{ char col1[MAX_ARG_LENGTH]; char col2[MAX_ARG_LENGTH]; }; struct unused_s unused[MAX_USEABLE]; const char* getunused(char* line, int n) { const char* tok; // strtok会破坏原字符串,这里传入的是strdup后的副本,无需担心原数据损坏 for (tok = strtok(line, ";"); tok && *tok; tok = strtok(NULL, ";\n")) { if (!--n) { // 提前截断过长的列内容,避免后续拷贝溢出 static char buf[MAX_ARG_LENGTH]; strncpy(buf, tok, MAX_ARG_LENGTH - 1); buf[MAX_ARG_LENGTH - 1] = '\0'; return buf; } } // 找不到对应列时返回空字符串,避免传入NULL给strcpy return ""; } void readCSV(FILE *file){ int i = 0; char line[MAX_LINE_LENGTH]; // 限制循环次数,彻底避免数组越界 while (i < MAX_USEABLE && fgets(line, MAX_LINE_LENGTH, file)) { // 跳过空行,减少无效处理 if (strlen(line) <= 1) continue; char* tmp = strdup(line); if (!tmp) { perror("strdup内存分配失败"); break; } const char* col1_val = getunused(tmp, FIRST_COLUMN); const char* col2_val = getunused(tmp, SECOND_COLUMN); // 用strncpy替代strcpy,强制限制拷贝长度,防止缓冲区溢出 strncpy(unused[i].col1, col1_val, MAX_ARG_LENGTH - 1); unused[i].col1[MAX_ARG_LENGTH - 1] = '\0'; strncpy(unused[i].col2, col2_val, MAX_ARG_LENGTH - 1); unused[i].col2[MAX_ARG_LENGTH - 1] = '\0'; free(tmp); i++; } fclose(file); }
额外排查建议
- 用
gdb调试:编译时加上-g参数,运行gdb ./你的程序名,触发段错误后输入bt命令,就能看到精准的出错调用栈。 - 确认
MAX_USEABLE的值是否足够容纳CSV的总行数,避免数组容量不足。 - 检查CSV文件格式,确认所有行的分隔符都是
;,没有异常换行或空列的情况。
内容的提问来源于stack exchange,提问作者Gabriel Vega
相关产品推荐
相关产品推荐

