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

C语言中检查char*是否在LabelList的函数异常返回0的排查与解决

CSV标签数据加载问题排查与解决

问题背景

我的程序需要从CSV文件加载数据,每行最后一段是对应数据点的标签。由于标签会重复,我采用存储标签列表、让程序内数据存储标签索引的方式提升效率。标签列表的初始实现如下(后续会补充temp == NULL的错误处理逻辑):

typedef struct _LabelList {
    size_t size;
    char **label_table;
} LabelList;

void add_label(LabelList *list, char *label) {
    if (list->label_table == NULL) {
        list->size = 1;
        char **temp = malloc(sizeof(char *));
        if (temp != NULL) {
            list->label_table = temp;
            list->label_table[0] = label;
        }

        return;
    }
    else {
        list->size++;
        size_t temp_size = list->size;
        char **temp = realloc(list->label_table, temp_size * sizeof(char *));
        if (temp != NULL) {
            list->label_table = temp;
            list->label_table[temp_size-1] = label;
        }

        return;
    }
}

问题现象

check_if_exists函数单独测试时运行正常:若传入的char*在列表中则返回索引,否则返回-1,但被其他函数调用时出现异常。具体表现为:第一个标签能正常添加到label_list,但后续调用create_labeled_data_point时,check_if_exists始终返回0——排查发现该函数内label_list的第一个元素始终与to_check参数相同,导致strcmp每次都返回0。最初用链表实现时也遇到了同样的问题。

相关问题函数代码如下:

int check_if_exists(LabelList list, char *to_check) {
    size_t length = list.size;
    int exists;

    for (size_t i = 0; i < length; i++) {
        exists = strcmp(list.label_table[i], to_check);
        if (exists == 0) return i;
    }

    return -1;
}

LabeledDataPoint *create_labeled_data_point(char *data, size_t rec_count, LabelList *label_list) {
    char *token;
    char *end;
    LabeledDataPoint *point = malloc(sizeof(size_t) + rec_count*sizeof(double) + sizeof(char *));
    
    point->dims = rec_count-1;

    token = strtok(data, ",");
    point->data[0] = atof(token);

    for (size_t i = 1; i < rec_count-1; i++) {
        token = strtok(NULL, ",");
        point->data[i] = atof(token);
    };

    token = strtok(NULL, ",");

    int index_in_list = check_if_exists(label_list, token);

    if (index_in_list == -1) {
        add_label(label_list, token);
        point->label_num = label_list->size-1;
    }
    else {
        point->label_num = index_in_list;
    }

    return point;
}

LabeledDataPoint **load_labeled_data_csv(FILE *file, size_t num_records, size_t num_fields, LabelList *label_list) {
    LabeledDataPoint **all_data = malloc(num_records*(sizeof(size_t) + num_fields*sizeof(double)));

    LabeledDataPoint *current_data_point;
    char *current_record = NULL;
    size_t n = 0;
    int chars_num;

    for (size_t i = 0; i < num_records; i++) {
        chars_num = getline(&current_record, &n, file);
        if (chars_num != -1) {
            current_data_point = create_labeled_data_point(current_record, num_fields, label_list);
        }
        all_data[i] = current_data_point;
    }
    free(current_record);

    return all_data;
}

解决方法

经过调整,修改了两个核心函数,同时新增内存释放函数避免内存泄漏:

修改后的create_labeled_data_point函数

LabeledDataPoint *create_labeled_data_point(char *data, size_t rec_count, LabelList *label_list) {
    char *token;
    char *end;
    LabeledDataPoint *point = malloc(sizeof(size_t) + rec_count*sizeof(double) + sizeof(char *));
    
    point->dims = rec_count-1;

    token = strtok(data, ",");
    point->data[0] = atof(token);

    for (size_t i = 1; i < rec_count-1; i++) {
        token = strtok(NULL, ",");
        point->data[i] = atof(token);
    };

    token = strtok(NULL, ",");

// 复制最后一个token,原data指针可安全释放
    char *token_copy = malloc(strlen(token)+1);
    strcpy(token_copy, token);

    int index_in_list = check_if_exists(*label_list, token);

// 标签已存在则释放复制的token,否则保留token待列表废弃时统一释放
    if (index_in_list == -1) {
        add_label(label_list, token_copy);
        point->label_num = label_list->size-1;
    }
    else {
        point->label_num = index_in_list;
        free(token_copy);
    }

    return point;
}

修改后的load_labeled_data_csv函数

LabeledDataPoint **load_labeled_data_csv(FILE *file, size_t num_records, size_t num_fields, LabelList *label_list) {
    LabeledDataPoint **all_data = malloc(num_records*(sizeof(size_t) + num_fields*sizeof(double)));

    LabeledDataPoint *current_data_point;
    char *current_record = NULL;
    size_t n = 0;
    int chars_num;

    for (size_t i = 0; i < num_records; i++) {
        chars_num = getline(&current_record, &n, file);
        if (chars_num != -1) {
            current_data_point = create_labeled_data_point(current_record, num_fields, label_list);
        }
        all_data[i] = current_data_point;
 // 每次循环后释放current_record并重置为NULL
       free(current_record);
        current_record = NULL;
        n = 0;
    }

    return all_data;
}

新增内存释放函数free_label_list

void free_label_list(LabelList *list) {
    size_t size = list->size;

    for (size_t i = 0; i < size; i++) {
        free(list->label_table[i]);
    }

    free(list->label_table);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:05:54