C语言链表函数行为差异疑问:delEven与delAll2为何效果不同?
C语言链表删除函数的指针操作差异问题
我在练习C语言链表时遇到一个疑问:创建存储1-10的链表后,delEven()函数通过P = *node操作能正常删除偶数元素,但用同样方式写的delAll2()却无法清空链表;而直接操作*node的delAll()功能正常。想搞清楚这两个函数行为不同的原因。
测试代码
#include <stdio.h> #include <stdlib.h> struct node { int dat; struct node* next; }; void printList (struct node* node) { if (node == NULL) { printf("empty\n"); return; } while (node->next!=NULL) { printf("%2d",node->dat); node = node->next; } printf("%2d\n",node->dat); } void delEven(struct node** node) { struct node* P; P = *node; while (P->next != NULL) { if (P->next->dat%2==0) { P->next = P->next->next; } if(P->next->dat%2==0) { P->next = P->next->next; } P=P->next; } } void delAll(struct node** node) { struct node* P; P = *node; while ((*node)->next != NULL) { *node = (*node)->next; } *node = (*node)->next; } void delAll2(struct node** node) { struct node* P; P = *node; while (P != NULL) { P = P->next; } } void main() { int i; struct node* start; struct node* Q; struct node* P; start = NULL; for(i=1; i<=10;i++) { Q=malloc(sizeof(struct node)); Q->dat = i; Q->next = start; start = Q; } printList(start); printList(start); delEven(&start); printList(start); delAll2(&start); printList(start); }
输出结果
使用delAll2()时的输出
10 9 8 7 6 5 4 3 2 1 10 9 8 7 6 5 4 3 2 1 10 9 7 5 3 1 10 9 7 5 3 1
使用delAll()时的输出
10 9 8 7 6 5 4 3 2 1 10 9 8 7 6 5 4 3 2 1 10 9 7 5 3 1 empty
原因解析
1. delEven()能生效的本质
delEven()中,P = *node让局部指针P指向原链表的头节点,后续操作的是P->next——也就是修改链表节点自身的next成员。这些节点属于原链表的一部分,修改它们的next指针会直接改变原链表的结构关系,所以删除操作的结果能被外部的start指针感知到。
2. delAll2()无效的核心问题
delAll2()里只是让局部指针P不断向后移动(P = P->next),直到P变为NULL。这个操作仅改变了局部变量P的指向,既没有修改原链表的任何节点,也没有改动*node(即外部的start指针)的值。外部的start仍然指向原来的头节点,自然链表没有任何变化。
3. delAll()生效的原因
delAll()直接操作*node(也就是外部start指针的地址),不断将*node的指向往后移动,最后把*node置为NULL。这相当于直接修改了外部的start指针,让它指向空地址,所以外部打印时显示链表为空。
额外提示
delAll()存在内存泄漏:它仅将start置为NULL,但未释放链表节点占用的内存,正确的清空逻辑应该逐个调用free()释放每个节点。delEven()存在功能缺陷:如果头节点本身是偶数,不会被删除;连续偶数的处理逻辑也有漏洞(比如两个偶数连续时,第二个可能跳过判断)。
内容的提问来源于stack exchange,提问作者krustykay
相关产品推荐
相关产品推荐

