C语言链表元素查找复制返回异常:free操作致结果错误
嘿,我一眼就get到你遇到的问题了——你大概率是在复制节点内容的时候只做了浅拷贝,而不是深拷贝!这就导致新节点看起来是独立的,但实际上它的某些成员还和原节点共享同一块内存,free原节点后,这块内存就失效了,新节点的内容自然就不对了。
我给你拆解下核心原因和解决办法:
问题根源:浅拷贝的陷阱
如果你的链表节点结构体里包含指针类型的成员(比如char *字符串、指向其他结构体的指针),你只是把原节点里的指针值直接复制到新节点中,那新节点的指针和原节点的指针其实指向同一块内存空间。这时候你free原节点,不管是原节点结构体本身被释放,还是原节点释放时连带释放了指针指向的内存,新节点里的指针都会变成野指针,访问它的内容就是未定义行为,结果自然不正确。举个具体的例子,假设你的节点结构体是这样的:
typedef struct ListNode { int val; char *data; struct ListNode *next; } ListNode;如果你复制的时候只写了:
ListNode *new_node = malloc(sizeof(ListNode)); new_node->val = old_node->val; new_node->data = old_node->data; // 这里只是复制指针,不是实际数据!那
new_node->data和old_node->data指向同一个字符串。当你free(old_node)后,如果old_node->data是和节点一起分配的内存,那这块内存就被回收了,new_node->data指向的就是无效区域,内容肯定不对。正确做法:深拷贝实现完全独立
要让新节点真正独立,你需要对所有指针类型的成员做深拷贝——也就是给新节点的指针成员重新分配内存,然后把原节点指针指向的实际内容复制过去。比如上面的data成员:ListNode *new_node = malloc(sizeof(ListNode)); if (!new_node) { // 处理内存分配失败 return NULL; } new_node->val = old_node->val; // 深拷贝字符串 new_node->data = malloc(strlen(old_node->data) + 1); if (!new_node->data) { // 分配失败要回滚,避免内存泄漏 free(new_node); return NULL; } strcpy(new_node->data, old_node->data);这样
new_node->data指向的是一块全新的内存,和原节点的内存完全无关,就算你free原节点,新节点的内容也不会受到任何影响。额外注意:原节点的释放要彻底
另外,你在free原节点的时候,要确保如果原节点的指针成员是动态分配的,也要先free这些成员,再free节点本身,避免内存泄漏。比如:free(old_node->data); free(old_node);当然,这一步的前提是
old_node->data确实是动态分配的,不然会导致双重free错误。
总结一下:你以为新元素是独立实例,但浅拷贝让它和原元素共享了底层内存。只有做深拷贝,才能让新节点完全脱离原节点的依赖,这时候再free原节点就不会影响新节点的内容啦。
内容的提问来源于stack exchange,提问作者Vlad Nicola

