You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言CSV解析函数访问已分配数组出现Segmentation fault段错误

问题核心原因与修复方案

你的代码存在多处内存管理和参数传递的逻辑错误,直接导致段错误:

  • 参数传递层级错误:你需要在函数内修改外部传入的char*数组指针本身,所以入参应该声明为char*** data,而不是char** data。当前写法下函数内对data的赋值仅修改局部变量,外部实参不会拿到你分配的内存地址,传入NULL的情况下直接访问就是野指针。
  • 二维数组内存分配逻辑完全错误:char**是指针数组,每个元素指向一个独立的字符串内存块,你不能直接用*size * *str_size的大小分配整块内存。这种分配方式下data[data_count]读取的是内存块前几位的内容作为地址,本质是非法的野指针访问,是触发data[0][0]访问崩溃的直接原因。
  • 扩容逻辑错误:数组元素个数不足时应该扩容指针数组,单个字符串长度不足时应该扩容对应下标的字符串内存,你当前所有扩容都直接重分配data,计算逻辑完全错误,会直接破坏内存结构。
  • fscanf返回值判断错误:fscanf读取失败时返回EOF(值为-1),直接放在while判断条件中会被识别为真,导致文件读完后循环不会退出。
修正后的代码
/**
 * @brief 通过首个字段从CSV文件中读取指定行,动态分配内存给data数组
 * 
 * @param file 打开的CSV文件指针
 * @param key 要匹配的行首字段
 * @param data 出参,存储解析后的字符串数组,使用完需要调用者逐元素free后再free本身
 * @param size 出参,存储返回的数组长度
 * @param str_size 入参,指定每个字符串的初始分配大小,传0则使用默认值
 * @return 0 成功,-1 未找到对应行,1 入参非法
 */
int csv_get_row(FILE *file, char *key, char ***data, size_t *size, size_t *str_size) {
    if(!file || !key || !data || !size || !str_size) return 1;

    /* 获取匹配key的行起始偏移 */
    long pos = find_key(file, key);
    if(pos == -1) return -1;
    fseek(file, pos, SEEK_SET);

    /* 初始化默认参数 */
    if(*size < 1) *size = DEFAULT_ARRAY_SIZE;
    if(*str_size < 1) *str_size = DEFAULT_BUFFER_SIZE;

    /* 分配指针数组内存 */
    *data = (char**) malloc(*size * sizeof(char*));
    if(!*data) return 1;
    /* 初始化第一个字符串的内存 */
    (*data)[0] = (char*) malloc(*str_size * sizeof(char));
    if(!(*data)[0]) return 1;

    size_t data_count = 0;
    size_t str_pos = 0;
    char curr;
    /* 正确判断fscanf读取成功 */
    while(fscanf(file, "%c", &curr) == 1) {
        /* 指针数组扩容 */
        if(data_count >= *size) {
            *size *= 2;
            char** new_data = (char**) realloc(*data, *size * sizeof(char*));
            if(!new_data) return 1;
            *data = new_data;
        }
        /* 当前字符串扩容 */
        if(str_pos >= *str_size) {
            *str_size *= 2;
            char* new_str = (char*) realloc((*data)[data_count], *str_size * sizeof(char));
            if(!new_str) return 1;
            (*data)[data_count] = new_str;
        }

        if(curr == ',') {
            (*data)[data_count][str_pos] = '\0';
            data_count++;
            str_pos = 0;
            /* 为下一个字符串预分配内存 */
            (*data)[data_count] = (char*) malloc(*str_size * sizeof(char));
            if(!(*data)[data_count]) return 1;
            continue;
        }

        if(curr == '\n') {
            (*data)[data_count][str_pos] = '\0';
            data_count++;
            break;
        }

        (*data)[data_count][str_pos] = curr;
        str_pos++;
    }

    /* 裁剪数组到实际长度 */
    *size = data_count;
    char** new_data = (char**) realloc(*data, *size * sizeof(char*));
    if(new_data) *data = new_data;

    return 0;
}
调用注意事项

调用该函数时需要传入char**变量的地址,示例如下:

char** data = NULL;
size_t size = 0;
size_t str_size = 0;
int ret = csv_get_row(file, "target_key", &data, &size, &str_size);
// 使用完data后需要释放内存
for(size_t i=0; i<size; i++) {
    free(data[i]);
}
free(data);

内容的提问来源于stack exchange,提问作者Thomas Beatty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 18:06:00