C语言双向链表删除首尾节点为何需返回指针?指针传值疑惑
双向链表删除节点的指针传递问题
先看这段删除双向链表节点的C语言函数:
#include <stdlib.h> typedef struct node { struct node *before; struct node *next; // 可按需添加数据域 } node; node *delete(int x, node *new) { node *del = new; for (int i = 0; i < x; i++) { del = del->next; } // 删除首节点 if (del->before == NULL) { del = del->next; node *rem = del->before; del->before = NULL; new = del; free(rem); return new; } // 删除尾节点 else if (del->next == NULL) { del = del->before; node *rem = del->next; del->next = NULL; free(rem); return new; } // 删除中间节点 else { del->before->next = del->before->next->next; del->next->before = del->next->before->before; free(del); return new; } }
核心原因:C语言的指针是按值传递
C语言中所有参数都是按值传递,指针也不例外。函数里的new是你传入的链表头指针的副本——它和主函数里的原指针指向同一块内存,但本身是两个独立的变量。
1. 删除中间节点无需返回的原因
删除中间节点时,我们修改的是链表节点内部的指针成员:把被删节点的前一个节点的next指向后一个节点,后一个节点的before指向前一个节点。这些操作直接修改了堆内存中节点结构体的内容,主函数里的头指针本身没有变化(依然指向原来的头节点),所以外部能直接看到链表结构的更新,不需要修改头指针的值。
2. 删除首/尾节点的区别
- 删除首节点:原来的头节点被释放,必须让主函数里的链表头指针指向新的头节点(原第二个节点)。但函数里的
new是原指针的副本,修改new = del只是改变了副本的值,主函数里的原指针完全不受影响。因此必须把新的头指针返回,让主函数重新赋值(比如head = delete(0, head);),才能更新外部的链表指针。 - 删除尾节点:这里返回
new其实是多余的——头指针本身没有变化,我们只是修改了倒数第二个节点的next为NULL,主函数里的头指针依然指向原头节点,链表尾端已经被正确截断。你测试时觉得需要返回,只是因为代码里统一写了return,实际不返回也不影响结果。
补充优化建议
如果不想通过返回值更新头指针,可以改用指向指针的指针作为参数,直接修改主函数里的指针变量。比如把函数签名改成void delete(int x, node **new),删除首节点时直接修改*new = del,就能同步更新外部的头指针,无需返回值。
内容的提问来源于stack exchange,提问作者rowley
相关产品推荐
相关产品推荐

