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

求助:C语言动态分配字符串数组去重及内存释放方法

嘿,我来帮你搞定这个动态数组去重+内存释放的问题,顺便帮你捋捋Valgrind报的内存泄漏和段错误到底咋回事~

先明确核心思路:动态数组去重的正确姿势

你的单词统计程序里,应该是用动态数组(比如char** words)存储读取到的单词,再搭配一个计数数组记录每个单词的出现次数。去重的时候必须同时做到:合并重复单词的计数、释放重复单词占用的内存、调整数组结构避免越界或泄漏。

第一步:先对齐你的数据结构

假设你用的是这类常见的统计结构(如果你的结构不一样,按需调整就行):

typedef struct {
    char** words;       // 存储所有读取到的单词(可能含重复)
    int* counts;        // 对应每个单词的出现次数
    int size;           // 当前数组的实际元素数量
    int capacity;       // 数组的总容量(用来避免频繁扩容)
} WordStats;

第二步:去重+内存释放的具体实现

下面给你一个可复用的示例函数,你可以直接套进自己的代码里:

void removeDuplicates(WordStats* stats) {
    if (stats->size == 0) return; // 空数组直接返回

    // 用calloc初始化标记数组,默认值0表示非重复
    int* isDuplicate = calloc(stats->size, sizeof(int));
    if (!isDuplicate) {
        perror("Failed to allocate memory for duplicate marker");
        exit(EXIT_FAILURE);
    }

    int uniqueCount = 0;
    // 外层遍历每个单词,找后续的重复项
    for (int i = 0; i < stats->size; i++) {
        if (isDuplicate[i]) continue; // 已经标记为重复,跳过处理

        // 内层遍历找重复单词
        for (int j = i + 1; j < stats->size; j++) {
            if (!isDuplicate[j] && strcmp(stats->words[i], stats->words[j]) == 0) {
                stats->counts[i] += stats->counts[j]; // 合并计数
                free(stats->words[j]); // 关键:释放重复单词的内存
                isDuplicate[j] = 1; // 标记为重复,后续跳过
            }
        }
        uniqueCount++;
    }

    // 为唯一单词和计数分配新内存
    char** newWords = malloc(uniqueCount * sizeof(char*));
    int* newCounts = malloc(uniqueCount * sizeof(int));
    if (!newWords || !newCounts) {
        perror("Failed to allocate memory for unique elements");
        free(isDuplicate);
        exit(EXIT_FAILURE);
    }

    // 把非重复元素拷贝到新数组
    int idx = 0;
    for (int i = 0; i < stats->size; i++) {
        if (!isDuplicate[i]) {
            newWords[idx] = stats->words[i];
            newCounts[idx] = stats->counts[i];
            idx++;
        }
    }

    // 释放旧数组的内存(注意:非重复单词的指针已经转移到新数组,不用单独free)
    free(stats->words);
    free(stats->counts);
    free(isDuplicate);

    // 更新结构体的指针和大小
    stats->words = newWords;
    stats->counts = newCounts;
    stats->size = uniqueCount;
    stats->capacity = uniqueCount; // 可以根据需求调整容量
}

第三步:排查Valgrind的报错问题

内存泄漏的常见坑:

  • 重复单词没释放:你可能只从数组里移除了重复单词的指针,但忘了free它指向的字符串内存
  • 旧数组没释放:扩容或者重新分配数组时,旧的words/counts数组没有被free
  • 程序退出前没清理:整个统计结构体的内存(包括每个单词、数组本身)都要在程序结束前释放

段错误的常见坑:

  • 访问已释放内存:重复单词被free后,后续代码还去读取它的内容
  • 数组越界:遍历数组时索引超出了size的范围,或者扩容时计算容量出错
  • 空指针解引用:动态分配内存后没检查是否成功,直接使用空指针

额外优化建议

其实你可以在读取单词的时候就去重,这样能减少后续的内存操作:每次读一个单词,先遍历已有的唯一单词,找到就把对应计数+1,找不到再添加到数组里。这样既省内存,又避免了后期大规模的去重操作。

另外,程序结束时一定要记得清理所有动态内存,比如写一个释放函数:

void freeWordStats(WordStats* stats) {
    for (int i = 0; i < stats->size; i++) {
        free(stats->words[i]); // 先释放每个单词的内存
    }
    free(stats->words); // 再释放数组本身
    free(stats->counts);
    stats->size = 0;
    stats->capacity = 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:33:08