C语言链表实现出现invalid heap pointer错误的原因及疑问
C语言链表
invalid heap pointer错误分析与解惑 你的代码实现
LinkedList.c
#include <stdio.h> #include "function.h" int main(void) { //initialize struct Node myNode = { 10,NULL }; List head = &myNode; insert(20, head, head); makeEmpty(head); return 0; }
function.h
//this is the statement of the Linkedlist #ifndef _FUNCTION_H #define _FUNCTION_H struct Node; //pointer to the strcut Node typedef struct Node* PtrToNode; typedef PtrToNode List; typedef PtrToNode Position; struct Node { //a struct pointer that point to next struct int element; //body Position Next; /* data */ }; //清空整张链表 List makeEmpty(List L); //判断链表是否为空 int isEmpty(List L); int isLast(Position p, List L); Position Find(void* x, List L); void insert(int x, List L, Position P); #endif /*_function_h*/
List.c
#include "function.h" #include <stdio.h> #include <stdlib.h> List makeEmpty(List L) { Position cur = L; Position next; while (cur!= NULL) { next = cur->Next; free(cur); cur = next; } cur = NULL; next = NULL; //这里c是copy by value 所以改变那个指针,如果不赋值的话 //就是用void的话,不会将原来的指针改变。 L = NULL; return L; } //right int isEmpty(List L) { return L->Next == NULL; } int isLast(Position P, List L) { //判断P在不在List里 List cur = L; while (cur->Next != P) { cur = cur->Next; } if (cur == NULL) { fprintf(stderr, "there is no P in the list L\n"); return -1; } if (P->Next == NULL) { return 1; } else { return 0; } return -1; } void insert(int x, List L, Position P) { Position tmpCell; tmpCell = (Position)malloc(sizeof(struct Node)); if (tmpCell == NULL) { fprintf(stderr,"out of the space!\n"); } tmpCell->element = x; tmpCell->Next = P->Next; P->Next = tmpCell; }
1. invalid heap pointer错误原因
这个错误的核心是对栈内存执行了free操作:
- 在
main中,struct Node myNode是栈上分配的局部变量,内存由操作系统自动管理,不属于堆内存范畴,绝对不能用free释放。 - 你调用
makeEmpty(head)时,head指向的就是这个栈上的myNode,makeEmpty函数里的cur = L会指向栈内存,随后执行free(cur)——这是对非堆内存调用free,直接触发堆指针非法操作的错误。
2. 传head->Next程序正常的原因
当你把makeEmpty的参数改成head->Next时,传入的指针指向的是insert函数中用malloc创建的节点:
insert(20, head, head)会通过malloc在堆上分配新节点,这个节点的内存是合法的堆内存,可以用free释放。- 此时
makeEmpty只会遍历并释放这个堆节点,不会触碰栈上的myNode,因此不会触发非法释放的错误,程序可以正常运行。
3. 代码优化建议
3.1 统一使用堆内存管理链表节点
链表的头节点建议也用malloc分配,避免栈堆混合管理的问题:
// 修改main函数的初始化代码 int main(void) { List head = (List)malloc(sizeof(struct Node)); if (head == NULL) { fprintf(stderr, "out of space!\n"); return 1; } head->element = 10; head->Next = NULL; insert(20, head, head); head = makeEmpty(head); // 接收返回的NULL,避免悬空指针 return 0; }
这样整个链表的节点都在堆上,makeEmpty可以安全地释放所有节点,同时接收返回的NULL可以避免后续误操作悬空指针。
3.2 修复isEmpty的空指针风险
如果传入isEmpty的L是NULL,L->Next会触发空指针解引用,建议增加判断:
int isEmpty(List L) { return L == NULL || L->Next == NULL; }
3.3 修复isLast的遍历逻辑缺陷
原代码中如果P不在链表中,循环会一直遍历到cur变为NULL,此时访问cur->Next会触发空指针错误,修改如下:
int isLast(Position P, List L) { if (P == NULL || L == NULL) { fprintf(stderr, "invalid pointer input\n"); return -1; } List cur = L; while (cur != NULL && cur->Next != P) { cur = cur->Next; } if (cur == NULL) { fprintf(stderr, "there is no P in the list L\n"); return -1; } return P->Next == NULL; }
内容的提问来源于stack exchange,提问作者user22873067
相关产品推荐
相关产品推荐

