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
相关产品推荐
相关产品推荐

