首先你要搞明白,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的值,但不应该保存它的地址
说实话,还是建议楼主先搞清楚为什么要用二级指针,杀鸡用牛刀未必一定好~
while(p!=NULL)
{
list=&p->next; //这句话的意思是把p结点的next域的地址赋给list,list实际指向将要被释放的内存空间
free(p); //p结点释放,list就失效了
p=*list;
}
//结构定义
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;
}
-------------------------*/
}
list=&p->next;
改成
list=&(p->next);
试试看