指针技巧:独特的间接寻址

linus大佬的代码见解。原文:https://github.com/mkirchner/linked-list-good-taste

以删除链表的某个节点为例子,链表数据结构如下:

在这里插入图片描述

struct list_item {
        int value;
        struct list_item *next;
};
typedef struct list_item list_item;


struct list {
        struct list_item *head;
};
typedef struct list list;

删除的函数声明:

/* The textbook version */
void remove_cs101(list *l, list_item *target);
/* A more elegant solution */
void remove_elegant(list *l, list_item *target);

CS101实现:

在这里插入图片描述

void remove_cs101(list *l, list_item *target)
{
        list_item *cur = l->head, *prev = NULL;
        while (cur != target) {
                prev = cur;
                cur = cur->next;
        }
        if (prev)
                prev->next = cur->next;
        else
                l->head = cur->next;
}

优雅的实现:

在这里插入图片描述

void remove_elegant(list *l, list_item *target)
{
        list_item **p = &l->head;
        while (*p != target)
                p = &(*p)->next;
        *p = target->next;
}

优雅的实现原理:

首先l->head是指向列表第一项的指针,初始化一个list_item **类型的变量p,取指向head指针的地址(&l->head),使其赋给p。也就是说p是指针的指针。

接下来通过循环找到目标指针:更新p来遍历list, *p表示将指向当前列表项的指针的地址解引用,*p->next表示下一个列表项的地址,&再取地址的地址赋给p。

最后将目标节点移除(通过赋值方式来覆盖目标节点)。

为什么使用间接指针?

使用pre和cur需要判断null的情况,但是用间接指针可以避免这种状况,同时用地址更新的方法遍历,只需要单个迭代器。

扩展

将优雅的实现包装成查找函数

static list_item** find_index(list* l, list_item* target)
{
    list_item** p = &l->head;
    while (*p != target)
    {
        p = &(*p)->next;
    }
    return p;
}
void remove_elegant(list* l, list_item* target)
{
    list_item** p = find_index(l, target);
    *p = target->next;
}

在某个节点前插入:

void insert(list* l, list_item* before, list_item* item)
{
    list_item** p = find_index(l, before);
    *p = item;
    item->next = before;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值