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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 22:55:56