尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

一级指针与二级指针 —— 链表中必须掌握的核心概念

一级指针与二级指针 —— 链表中必须掌握的核心概念 一级指针与二级指针 —— 链表中必须掌握的核心概念在 C 语言中指针是灵魂而二级指针指向指针的指针更是让不少初学者头疼。但在链表操作中它却扮演着至关重要的角色。本文将结合具体代码深入剖析为什么修改头指针必须用二级指针以及一级指针和二级指针各自适合的场景。1. 函数参数的“值传递”本质C 语言中所有函数参数都是值传递——形参是实参的一份拷贝。这意味着可以使用但是不能修改在函数内部修改形参的值不会影响外部的实参。要想在函数内部修改外部变量必须传递该变量的地址指针。voidset_null(int*p){pNULL;// 修改的是形参 p外部指针不受影响}voidreal_set_null(int**p){*pNULL;// 解引用后修改的是外部指针变量本身}2. 一级指针能做什么不能做什么一级指针T*可以通过使用指向地址来解引用修改指针所指向的内存内容即*p value。通过使用指向地址访问结构体成员p-next。但一级指针不能修改它自己的指向地址值即无法改变外部指针变量存储的地址因为外部指针变量本身是按值传递的。举例修改结点的next指针 —— 一级指针足够typedefstructNode{intdata;structNode*next;}Node;// 让 p 结点的 next 指向 new_nodevoidchange_next(Node*p,Node*new_node){if(pNULL)return;p-nextnew_node;// 修改的是 p 所指向结构体的成员不影响 p 自身}这里只需一级指针因为我们修改的是结点的成员而非指针变量本身。我们可以使用指向地址而不能修改指向地址的本身。3. 何时需要二级指针—— 修改头指针的场景头指针head是一个指向第一个结点的指针变量。插入或删除头结点时head本身存储的地址可能会改变。这里可见我们需要改变传入的指向地址本身所以必须要再套一层地址也就是使用二级指针。示例头插法插入新结点voidlist_head_insert(Node**head,Node*new_node){if(headNULL||new_nodeNULL)return;new_node-next*head;// 新结点指向原第一个结点*headnew_node;// 头指针指向新结点修改外部 head 变量}若不使用二级指针而写成void list_head_insert(Node *head, Node *new_node)则函数内部修改head new_node只影响形参外部的头指针永远不会更新链表丢失。4. 实战删除指定 id 的结点优雅的二级指针遍历下面这段代码利用二级指针不仅实现了删除还免去了处理“头结点特殊”的冗余逻辑staticintstudent_delete(Student**head,intid){Student**linkhead;// link 指向当前要检查的指针变量while(*link!NULL(*link)-id!id){link(*link)-next;// 向后移动link 指向下一个结点的指针域}if(*linkNULL)return0;// 未找到Student*removed*link;// 要删除的结点*linkremoved-next;// 将前驱的 next 指向被删结点的后继free(removed);return1;}为什么这么写link是一个二级指针它指向某个Student*类型的变量可能是头指针也可能是某个结点的next域。当遍历时link (*link)-next将link指向当前结点的next指针的地址这样在循环结束后*link就是待删除结点的前驱指针可能是头指针或某个next。删除时执行*link removed-next直接修改前驱指针的指向完美处理头结点删除此时link head修改*head。如果不使用二级指针删除头结点时不得不单独判断代码会变得冗长且容易出错。5. 另一种方案用结构体包装头指针一级指针也能行如果你实在不喜欢二级指针可以在结构体外层加一个“链表头”结构体也就是将你要修改的指向地址本身作为一个结构体的成员然后在函数中通过这个成员来修改。本质上也是外套一个地址。typedefstructLinkedList{Node*head;}LinkedList;// 插入函数只需一级指针voidlist_head_insert(LinkedList*list,Node*new_node){new_node-nextlist-head;list-headnew_node;}此时传入的是LinkedList*一级指针通过它修改head成员。本质上仍是传递了“头指针所在地址”只是换了一种形式。但这种方式增加了结构体开销对于简单链表二级指针更加直接。6. 总结与建议操作所需指针级别原因修改结点的成员如next、data一级指针只需找到结点修改其内容修改头指针的值插入/删除头结点二级指针需要修改外部指针变量本身的地址值遍历链表并删除任意结点二级指针简化逻辑统一处理头结点和中间结点黄金法则若要在函数内修改一个指针变量的值就必须把该指针变量的地址传进去 —— 即二级指针或者将该指针变量本身作为结构体的成员然后在函数中通过这个成员来修改。外部函数只能够使用而不能够直接修改如果觉得有用欢迎点赞、收藏、转发如有疑问欢迎留言讨论。
返回列表