如何妙用二级指针

本文介绍了一种利用二级指针优化单向链表删除操作的方法,避免了传统方法中需要额外指针及边界条件判断的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果要删除单向链表会如何做呢,很多人可能会使用一个Pre指针(很多教科书上也是如此实现的),如下代码

typedef struct node 
{     
	struct node * next;    
	.... 
} node;   
typedef bool (* remove_fn)(node const * v);  
// Remove all nodes from the supplied list for which the 
// supplied remove function returns true. 
// Returns the new head of the list. 
node * remove_if(node * head, remove_fn rm) 
{     
	for (node * prev = NULL, * curr = head; curr != NULL; )    
	{         
		node * const next = curr->next;        
		if (rm(curr))         
		{        
			if (prev)              
				prev->next = next;        
			else               
				head = next;  
			free(curr);         
		}        
		else     
			prev = curr;        
		curr = next;   
	}    
	return head; 
}
这里remove_fn由调用查提供的一个是否删除当前实体结点的函数指针,其会判断删除条件是否成立。这段代码维护了两个节点指针prev和curr,
标准的教科书写法——删除当前结点时,需要一个previous的指针,并且还要这里还需要做一个边界条件的判断——curr是否为链表头。
于是,要删除一个节点(不是表头),只要将前一个节点的next指向当前节点的next指向的对象,即下一个节点(即:prev->next = curr->next),然后释放当前节点。但是这样代码些是没能使用好指针的结果。下面代码演示了如何秒用二级指针对单链表进行删除

void remove_if(node ** head, remove_fn rm) 
{    
	for (node** curr = head; *curr; )     
	{         
		node * entry = *curr;       
		if (rm(entry))       
		{           
			*curr = entry->next;         
			free(entry);         }       
		else           
			curr = &entry->next;   
	} 
}
可以先理解下 下面这段代码:

#include <iostream>
using namespace std;



int main()
{
	list_t lA, lB, lC, lD;
	list_t ** phead = &lA.next; 

	lA.next = &lB;
	lA.a = 11;
	lA.b = 12;

	lB.next = &lC;
	lB.a = 21;
	lB.b = 22;

	lC.next = &lD;
	lC.a = 31;
	lC.b = 32;

	lD.next = NULL;
	lD.a = 41;
	lD.b = 42;

	printf("%d\n", ((list_t *)phead)->a);
	printf("%d\n", (*(list_t**)phead)->a);
	printf("%d\n", (**(list_t***)phead)->a);
	printf("%d\n", (***(list_t****)phead)->a);

	printf("%d\n", ((list_t *)phead)->b);
	printf("%d\n", (**(list_t**)phead).b);
	printf("%d\n", (***(list_t***)phead).b);
	printf("%d\n", (****(list_t****)phead).b);
	
	system("pause");
	return 0;
}
这里能这么使用 主要是Sreuct 的地址和指向下一个Struct的地址是一样的,也就是说指向下一个Struct的指针必须是放在开头 不然这么使用时会有问题的。

换言之,如果一个单向链表,next是第一个字段,我们可以用一个二级指针dummy引用一条链表上的所有节点。
struct node **dummy = &head->next;
一次解引用*dummy指向头结点head
二次解引用**dummy指向head下一个节点
三次解引用*(*(*dummy))指向第三个节点
以此类推……
如果我们需要找到从head开始的第N个节点,那么对dummy进行N次解引用即可,当然现实工程中一般不会用到这么tricky的语法糖,但使用一个变量同时引用相邻三个节点是很有用的;-)。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值