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

free()函数调用总是崩溃,怀疑malloc使用存在问题

内存分配与释放崩溃问题分析及修复

核心问题拆解

1. 结构体内存分配尺寸错误

createNewCont函数中,malloc(sizeof(newCont))是错误的——newCont是指针类型,大小仅为4/8字节,远小于Contact结构体的实际内存需求。这会导致结构体内存分配不足,后续访问成员时越界破坏堆结构,最终触发free崩溃。

2. 字符串内存未预留结束符空间

strlen(fName)返回的是有效字符长度,不包含字符串末尾的'\0',但strcpy需要写入这个结束符。直接用malloc(strlen(fName))分配内存,会导致字符串越界写入,破坏堆布局,引发free时的崩溃。

3. 野指针直接释放

createNewCont仅给firstName分配了内存,lastName和phoneNum完全未初始化(既没分配内存也没设为NULL),但freeParam中直接对这两个指针调用free,属于释放野指针,必然触发崩溃。

4. 创建函数未返回有效指针

createNewCont函数末尾没有return newCont;,调用后会得到随机垃圾指针,后续操作该指针会引发各种内存错误。

5. 释放函数逻辑缺失

freeParam仅处理了头节点的删除场景,未覆盖链表中间/尾节点的情况;且当头节点是唯一节点时,仅将head设为NULL,未释放任何内存,既造成泄漏也留下误操作风险。


修正后的代码

修复后的联系人创建函数

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct Contact {
    char* firstName;
    char* lastName;
    char* phoneNum;
    struct Contact* next;
} Contact;

Contact* createNewCont(char* fName, char* lName, char* phoNum)
{
    // 分配结构体完整内存,使用sizeof(Contact)而非指针大小
    Contact* newCont = malloc(sizeof(Contact));
    if (newCont == NULL) {
        return NULL;
    }

    // 处理firstName:分配内存时+1预留结束符,失败则回滚已分配内存
    newCont->firstName = malloc(strlen(fName) + 1);
    if (newCont->firstName == NULL) {
        free(newCont);
        return NULL;
    }
    strcpy(newCont->firstName, fName);

    // 处理lastName,同firstName逻辑
    newCont->lastName = malloc(strlen(lName) + 1);
    if (newCont->lastName == NULL) {
        free(newCont->firstName);
        free(newCont);
        return NULL;
    }
    strcpy(newCont->lastName, lName);

    // 处理phoneNum
    newCont->phoneNum = malloc(strlen(phoNum) + 1);
    if (newCont->phoneNum == NULL) {
        free(newCont->firstName);
        free(newCont->lastName);
        free(newCont);
        return NULL;
    }
    strcpy(newCont->phoneNum, phoNum);

    newCont->next = NULL; // 初始化next指针,避免野指针
    return newCont; // 返回有效结构体指针
}

修复后的联系人释放函数

#define TRUE 1
#define FALSE 0

int freeParam(Contact** head, char* fName, char* lName)
{
    if (*head == NULL) {
        printf("链表为空\n");
        return FALSE;
    }

    Contact* temp = *head;
    Contact* prev = NULL;

    // 遍历链表查找目标节点
    while (temp != NULL) {
        if (strcmp(temp->firstName, fName) == 0 && strcmp(temp->lastName, lName) == 0) {
            // 处理不同位置的节点删除
            if (prev == NULL) {
                *head = temp->next; // 删除头节点
            } else {
                prev->next = temp->next; // 删除中间/尾节点
            }

            // 按分配逆顺序释放内存
            free(temp->firstName);
            free(temp->lastName);
            free(temp->phoneNum);
            free(temp);
            temp = NULL;
            return TRUE;
        }
        prev = temp;
        temp = temp->next;
    }

    printf("未找到指定联系人\n");
    return FALSE;
}

关键注意事项

  • 所有malloc调用必须检查返回值是否为NULL,避免空指针操作。
  • 字符串分配内存必须预留'\0'的位置,即strlen(str) + 1。
  • 结构体的指针成员要么分配内存,要么初始化为NULL,杜绝野指针。
  • 释放内存时,先释放结构体成员的内存,再释放结构体本身,避免泄漏。
  • 链表操作要覆盖所有节点场景(头、中间、尾),避免逻辑漏洞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:31:06