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

Malloc触发SIGABRT信号:已释放对象校验和错误排查求助

问题根源分析与修复方案

从你给出的错误信息(Incorrect checksum for freed object)来看,这是堆内存被非法篡改导致的——通常是内存越界访问、重复释放或者内存泄漏破坏了malloc的内部管理结构。我帮你排查了代码里的几个关键问题,这些都是导致崩溃的直接原因:

1. 最致命的错误:fname内存分配过小导致越界

在main函数里,你只给fname分配了1个字符的空间:

char *fname = malloc(sizeof(char));

但用户输入的文件路径长度远大于1,scanf("%s", fname)会直接写爆这块内存,破坏堆的完整性,后续所有malloc/free操作都会出问题。

修复:
分配足够大的空间,或者用栈数组(如果路径长度可控),比如:

// 用栈数组更简单,避免手动管理内存
char fname[256];
printf("\n\n:::::::::::::: TASK 1 ::::::::::::::\n\nPlease Enter the Full Path of the file: \n");
scanf("%255s", fname); // 限制输入长度防止越界

如果坚持用malloc:

char *fname = malloc(256 * sizeof(char));
if (!fname) {
    perror("malloc failed");
    exit(EXIT_FAILURE);
}

2. string的内存操作严重错误

在task1的循环里,你有两个严重问题:

  • 每次循环都重新malloc(30*sizeof(char))给string,但之前的string没有释放,导致严重内存泄漏;
  • 用strcpy(&string[i],&tempHead->c)来复制单个字符是完全错误的——strcpy是用来复制以\0结尾的字符串的,这里你传入的是单个字符的地址,strcpy会一直读到\0,大概率越界写入,直接破坏堆结构。

修复:
应该直接给单个字符赋值,并且提前初始化string,用完及时释放(还要注意给字符串加结束符\0):

// 提前分配足够的空间,比如30个字符+1个结束符
string = malloc(31 * sizeof(char));
if (!string) {
    perror("malloc failed");
    exit(EXIT_FAILURE);
}
int i = 0;
// 遍历tempHead链表时直接赋值单个字符
Temp *tempPtr = tempHead;
while(tempPtr != NULL){
    if (i >= 30) break; // 防止越界
    string[i] = tempPtr->c;
    i++;
    tempPtr = tempPtr->next;
}
string[i] = '\0'; // 必须加字符串结束符,否则strcmp等函数会出错

另外,你现在的逻辑里每次处理一个大写字符就重新构建string,这逻辑本身也有问题,建议重新梳理单词拼接的逻辑——应该是遇到大写字母开始一个新单词,然后拼接后续的小写字母,直到遇到非小写字母为止,而不是反复遍历tempHead链表。

3. tempHead被错误遍历到NULL,导致后续链表操作失效

在第一个while(tempHead != NULL)循环里,你把tempHead一直遍历到NULL,之后再执行temp2->next = tempHead;时,tempHead已经是NULL了,而且原来的链表节点也丢失了,无法正确释放,导致内存泄漏,还可能引发非法访问。

修复:
遍历链表时用临时指针,不要修改原有的tempHead:

// 用tempPtr代替tempHead遍历,保留原链表头
Temp *tempPtr = tempHead;
int i = 0;
while(tempPtr != NULL){
    if (i >= 30) break;
    string[i] = tempPtr->c;
    i++;
    tempPtr = tempPtr->next;
}
string[i] = '\0';

4. main函数重复调用task1,导致文件指针失效+内存泄漏

你在main里连续调用了两次task1(fp, fname):

task1(fp, fname);
HistogramTemp *uniqueWordTempHead = task1(fp, fname);

第一次调用后,文件指针fp已经指向文件末尾,第二次调用task1时,fgetc(fp)直接返回EOF,什么都做不了;而且两次调用会创建两个独立的HistogramTemp链表,最后你只free了第二次的,第一次的链表完全泄漏,还可能因为重复操作堆内存导致崩溃。

修复:
只调用一次task1,保存返回值:

// 移除多余的第一次调用
HistogramTemp *uniqueWordTempHead = task1(fp, fname);

5. 内存释放不完整,导致泄漏+堆破坏

  • 在task1里,你只free(tempHead),但tempHead已经被遍历到NULL了,实际的temp1、temp2节点都没有被释放,导致内存泄漏;
  • uniqueWordTemp链表的节点(包括每个节点的words指针)也没有被逐个释放,main里只free(uniqueWordTempHead)是不够的,会导致严重内存泄漏。

修复:
编写链表释放函数,逐个释放节点:

// 释放Temp链表
void freeTempList(Temp *head) {
    Temp *temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp);
    }
}

// 释放HistogramTemp链表(包括每个节点的words)
void freeHistogramList(HistogramTemp *head) {
    HistogramTemp *temp;
    while (head != NULL) {
        temp = head;
        head = head->next;
        free(temp->words);
        free(temp);
    }
}

然后在task1里调用freeTempList(tempHead)代替free(tempHead),在main里调用freeHistogramList(uniqueWordTempHead)代替free(uniqueWordTempHead)。

额外调试建议

用valgrind工具来检查内存问题,它会帮你精准定位内存泄漏、越界访问的位置:

valgrind --leak-check=full ./untitled8

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:05:43