C语言链表中释放内存函数的问题,请高手解答。

//结构定义typedefstructnode{intitem;structnode*next;}Node;typedefNode*List;//释放内存函数voidFr... //结构定义
typedef struct node
{
int item;
struct node *next;
}Node;

typedef Node* List;
//释放内存函数
void FreeMem(List *list)
{
Node *p=*list;
Node *pt=NULL;
/*----------可行----------*/
while(p!=NULL)
{
pt=p->next;
free(p);
p=pt;
}

/*-------------------------
为什么用这种方式操作会出错?
while(p!=NULL)
{
list=&p->next;
free(p);
p=*list;
}
-------------------------*/
}
看看我哪里理解错了。
FreeMem(List *list);这样的定义list是指向一个节点的指针的指针。

*p=*list;是把节点的指针值复给p。p现在指向了第一个节点。
list=&p->next;将下一个节点指针的地址(也就是指针的指针)复制给list这个二级指针。现在list指向了第二个节点指针的地址。
free(p);p现在还是指向第一个节点,释放第一个节点的内存。
p=*list;现在将第二个节点的地址复制给p,使p指向第二个节点。
如此循环。
不知道哪里错了?
展开
 我来答
joseph_kitten
2013-05-22 · TA获得超过182个赞
知道答主
回答量:55
采纳率:0%
帮助的人:57.8万
展开全部
首先你要搞明白,List本身已经被定义为Node*类型,因此List*实际上是一个二级指针

你的疑问中,如果改成*list = p->next,运行应该是可以通过的。但是不推荐这样做。为什么呢?

这就要先理解FreeMem这个函数,为什么用List*做参数,而不是List。如果只是为了释放链表内存,只要一级指针就可以了,用二级指针只会增加代码的复杂程度,降低可读性。二级指针的作用就在于,在这个函数内,你可以修改这个函数的主调函数(比如main函数)中链表头结点的指针值。在这个例子中,显而易见的就是,链表释放了内存,head指针应该是NULL。

如果上面这段话你能明白的话,那么我的建议是,使用你问题中“可行”的那段代码,并添加*list = NULL;在结尾。或者这样做也可以达到同样的效果:传入参数使用一级指针,配合函数的返回值来保证功能的完整性,这样调用的时候需要诸如head = FreeMem(head);以达到释放内存后置head指针为NULL的目的。

看了楼主的追问,看来楼主对二级指针的理解还不太到位。其实mornslit兄的解释已经说清楚你这种写法的问题在哪了。我再帮你分析下:
pt = p->next;
*list = p->next;
这两种写法,效果是一样的,都是保存了下一个节点的地址(也就是p->next的值)
list = &p->next;
这种写法,是保存了p这个节点的next指针的地址,通过*运算,看似可以获取next的值,其实在p被free掉之后,next指针本身的值已经不能保证了
简言之,你错在哪了:p->next是下一个节点的地址,是与p共存亡的,你可以保存p->next的值,但不应该保存它的地址

说实话,还是建议楼主先搞清楚为什么要用二级指针,杀鸡用牛刀未必一定好~
百度网友83cdc1c
2013-05-21 · TA获得超过5792个赞
知道大有可为答主
回答量:1907
采纳率:100%
帮助的人:853万
展开全部
while(p!=NULL)
{
list=&p->next; //这句话的意思是把p结点的next域的地址赋给list,list实际指向将要被释放的内存空间
free(p); //p结点释放,list就失效了
p=*list;
}
追问
FreeMem(List *list);这样的定义list是指向一个节点的指针的指针。

*p=*list;是把节点的指针值复给p。p现在指向了第一个节点。
list=&p->next;将下一个节点指针的地址(也就是指针的指针)复制给list这个二级指针。现在list指向了第二个节点指针的地址。
free(p);p现在还是指向第一个节点,释放第一个节点的内存。
p=*list;现在将第二个节点的地址复制给p,使p指向第二个节点。
如此循环。
不知道哪里错了?
追答
*p=*list;这句话你断章取义了。全句是Node *p=*list,实际分两句:Node *p; p=*list;定义一个指向Node的指针p,然后把双重指针list的值(也就是头指针指向的地址)赋给p,这样p指向链表头。
逻辑上list=&p->next是把指向第二个结点的指针的地址赋给list了,问题是,这个指向第二个结点的指针存在于即将被释放的结点内,这个结点一旦被释放,list就指向了一个已经被释放的空间,那么*list的值就是无效的了。
本回答被提问者和网友采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
_梦幻阳光
2013-05-21 · TA获得超过978个赞
知道答主
回答量:219
采纳率:0%
帮助的人:175万
展开全部
//结构定义
typedef struct node
{
int item;
struct node *next;
}Node;

typedef Node* List;
//释放内存函数
void FreeMem(List *list) 这里就有问题了,List已经是指针了,把*去掉
{
Node *p=*list; 同理。把后面的*去掉
Node *pt=NULL;
/*----------可行----------*/
while(p!=NULL) 链表有头指针吗?如果有的话这里不行,
{ 需要将p指向list->next
pt=p->next;
free(p);
p=pt;
}

/*-------------------------
为什么用这种方式操作会出错? 看不懂你这里是干嘛?list一直指向同一块地址
while(p!=NULL) 把p指向的地址释放了,list指向的也就释放了
{
list=&p->next;
free(p);
p=*list;
}
-------------------------*/
}
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
ID鸡蛋炒韭菜
2013-05-21 · TA获得超过391个赞
知道小有建树答主
回答量:570
采纳率:50%
帮助的人:78.4万
展开全部
list=&p->next;

改成

list=&(p->next);

试试看
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(2)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式