美文网首页
利用二级指针管理单向链表

利用二级指针管理单向链表

作者: yiltoncent | 来源:发表于2018-10-26 16:01 被阅读9次

想写这样一篇站在巨人肩上的文章很久了,很久之前在CoolShell上就看到这篇文章:Linus:利用二级指针删除单向链表,当时第一眼看完十分之震惊,大神就是大神!这才是真正的Core Low-level Coding。

长久以来学习我们基础算法和数据结构,但是有多少人真的对基础的数据结构有这么深的钻研,上述链接文章中已经有详细的图解描述一次使用二级指针删除一个节点的实例。

我这里举一个Linux文件系统的例子,我使用linux-2.6.32版本,代码路径linux/fs/filesystems.c
其中需要讨论的代码,摘要如下:

struct file_system_type {
    const char *name;                   \\看这个
    int fs_flags;
    int (*get_sb) (struct file_system_type *, int,
               const char *, void *, struct vfsmount *);
    void (*kill_sb) (struct super_block *);
    struct module *owner;
    struct file_system_type * next;     \\看这个
    struct list_head fs_supers;

    struct lock_class_key s_lock_key;
    struct lock_class_key s_umount_key;

    struct lock_class_key i_lock_key;
    struct lock_class_key i_mutex_key;
    struct lock_class_key i_mutex_dir_key;
    struct lock_class_key i_alloc_sem_key;
};

static struct file_system_type *file_systems;

static struct file_system_type **find_filesystem(const char *name, unsigned len)
{
    struct file_system_type **p;
    for (p=&file_systems; *p; p=&(*p)->next)
        if (strlen((*p)->name) == len &&
            strncmp((*p)->name, name, len) == 0)
            break;
    return p;
}

int register_filesystem(struct file_system_type * fs)
{
    int res = 0;
    struct file_system_type ** p;

    BUG_ON(strchr(fs->name, '.'));
    if (fs->next)
        return -EBUSY;
    INIT_LIST_HEAD(&fs->fs_supers);
    write_lock(&file_systems_lock);
    p = find_filesystem(fs->name, strlen(fs->name));
    if (*p)
        res = -EBUSY;
    else
        *p = fs;
    write_unlock(&file_systems_lock);
    return res;
}

我要讨论的巧妙利用二级指针的代码就在find_filesystem函数中,其中struct file_system_type结构体可以先不理会,列出来也只是为了方便你看一些细节时候能找到对应的结构成员,不至于迷糊。

还是要从register_filesystem函数讲起,这个函数是将具体的文件系统注册到VFS,Linux中各文件系统初始化函数中都会调用这个函数。函数开始的时候定义了一个二级指针struct file_system_type ** p;,注意find_filesystem函数返回值直接赋值给了二级指针p,秘密都在这个函数里面。

find_filesystem函数中也首先定义了一个二级指针struct file_system_type ** p;在for循环初始化时将p指向了file_systems变量,这个file_systems变量就是VFS管理系统中所有实际文件系统的单向链表头,for循环在这里就是要遍历找到已经注册了VFS的文件系统的信息。for循环的判断条件是*p,即判断p指向是否为空,for循环的增量条件是p指向下一个struct file_system_type *结构。

中间循环就是进行比较判断,判断方法没得说,匹配上则break出来,直接return p,而如果整个链表都匹配不上,则循环结束的时候p=&(*p)->next,由于是最后一个链表了,所以最后链表的next项一定是null,这样返回的也是null

再回到上层函数,代码贴上来:

if (*p)
        res = -EBUSY;
else
        *p = fs;

已经很明了了,如果*p存在,即表示已经注册了这个文件系统了,则返回错误码;否则的话因为p已经指向最后一个链表的next域,那么*p = fs;表示最后一个链表的next被赋值为fs,即完成增加了单向链表。

后面再补一张图吧

总结

利用二级指针是Linux代码中一个常用trick,虽然有点绕,但是画一画图,人肉跑一跑代码逻辑,还是能搞得懂的,从代码看是简洁的,效率上看是高效的,不需要多余的中间变量和考虑边界条件。

相关文章

  • 利用二级指针管理单向链表

    想写这样一篇站在巨人肩上的文章很久了,很久之前在CoolShell上就看到这篇文章:Linus:利用二级指针删除单...

  • 单向链表

    参考我的博客 单向链表(LinkedList) 链表 链表二级指针的骚操作配合Debug观察内存状况更加容易学习!...

  • 数据结构基础--单向循环链表

    单向循环链表 单向循环链表是可循环的单链表,它与单链表的区别在于单向链表的最后一个元素的指针域为空,而单向循环链表...

  • 单向链表的排序

    单向链表的排序 最简单的做法是使用辅助数组,数组里存的是指针和value值,然后排序成功后,重新利用指针调整链表的...

  • 单向循环列表(创建/循环遍历/插入/查找/删除算法实现)

    单向循环列表 是什么呢? 与单向链表的区别就是,单向链表的最后一个节点指针是指向 NULL 的,单向循环链表最后一...

  • 数据结构-链表

    相关掌握点 单向链表 双向链表 反转单向链表 判断链表是否含有环 链表构建 链表是一种线性结构,是通过指针引用节点...

  • C语言指针部分说明

    二级指针 函数指针 数组和链表 访问数组 访问链表 Makefile

  • 数据结构与算法4-单向循环链表

    单向循环链表结构体设计 与单向链表区别之处在于单向链表的最后的结点的指针域 next 是设置为 null. 但是单...

  • 数据结构与算法第二讲:[单向循环链表]

    单向循环链表 单向循环链表:单链表的最后一个节点的指针指向链表头部,而不是指向NULL,那么就构成了一个单向循环链...

  • 单向循环链表总结

    注 :与单向链表区别之处在于单向链表的最后的结点的指针域next是设置为null. 但是单向循环链表最后一个结点是...

网友评论

      本文标题:利用二级指针管理单向链表

      本文链接:https://www.haomeiwen.com/subject/gmoktqtx.html