c语言内核链表list.h的解释及应用_c笔记

文章介绍了如何使用C语言实现循环链表的数据结构,并展示了如何在学生管理系统中运用这些链表操作,包括插入、删除、遍历等函数的定义和使用。

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

#ifndef __DLIST_H
#define __DLIST_H

/*
目的是在一个大的结构体中用一个小的结构体来实现循环链表,
这样就可以用小的结构体来进行next和pre的指向操作,
大的结构体就用来存各种信息。
*/

/*
offsetof这个宏,功能是测量在某个结构体中,某个成员的起始地址距离结构体的
起始地址的大小是多少。
这个宏有两个参数,第一个是TYPE,第二个是MEMBER。TYPE就是结构体名,
MEMBER是结构体中的某个成员。首先将0转换成TYPE类型的指针,然后指向
传入的成员。再然后取这个成员的地址,最后,size_t是无符号整数类型,
也就是把这个成员的地址转换成一个值。
以此获得成员的相对于结构体起始地址的偏移量。
*/
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)

/*
定义了一个宏container_of,目的是获取大结构体的起始地址,
有三个参数ptr,type,member。
{}的目的是让两条语句成为一个语块,()的目的是防止语法错误。
typeof可以测量变量或表达式的类型。
*/
#define container_of(ptr, type, member) ({ \
    const typeof( ((type *)0)->member) *__mptr=(ptr);\
    (type *)( (char*)__mptr-offsetof(type, member));})

//定义了两个非法地址。
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200)

//小结构体的声明,其中有前后指针。
struct list_head{
    struct list_head *next, *prev;
};

/*
这两句宏定义有关链表操作的功能。
宏LIST_HEAD_INIT(name)用于初始化一个链表头节点。
它创建一个struct list_head类型的结构体,
并将其next和prev成员指向该节点自身,形成一个空的循环链表。
宏LIST_HEAD(name)用于定义一个链表头节点。
它使用LIST_HEAD_INIT(name)宏初始化一个链表头节
点,并将其赋值给一个名为name的变量。通过这个宏定义,
我们可以方便地定义和初始化链表头节点。
*/
#define LIST_HEAD_INIT(name) { &(name), &(name)}
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)

/*
INIT_LIST_HEAD这个宏,内容是一个do while循环。
循环应该只会执行一次,会把小结构体的next和prev
指向自身,以成为双向循环链表。
*/
#define INIT_LIST_HEAD(ptr) do{\
    (ptr)->next = (ptr); (ptr)->prev = (ptr);\
}while(0)

/*
定义了一个静态的内联的void型函数__list_add,其目的是插入新节点。
传入的是三个list_head类型指针,在最开始有声明。
函数体的内容是十分基操的双向循环链表新节点的插入操作。
*/
static inline void __list_add(struct list_head *new_node, struct list_head *prev, struct list_head *next)
{
    next->prev = new_node;
    new_node->next = next;
    new_node->prev = prev;
    prev->next = new_node;
}

// static inline void __align_pre_next(struct list_head *node)
// {
//     node->next->prev = node->prev;
//     node->prev->next = node->next;
// }

/*
这个list_add函数是上一个__list_add函数的一个封装,
传入参数,然后进行插入,是往head的后面插。
*/
static inline void list_add(struct list_head *new_no, struct list_head *head)
{
    __list_add(new_no, head, head->next);
}

/*
同样是插入新节点,但是是往后插,一样是用__list_add函数
改变参数位置就可以往head的前面插。
*/
static inline void list_add_tail(struct list_head *new_no, struct list_head *head)
{
    __list_add(new_no, head->prev, head);
}

/*
prev和next中间还有一个节点,默认的,
所以通过互相指向以删除中间的节点。
*/
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
    next->prev = prev;
    prev->next = next;
}

/*
传入的是要删除的节点,通过__list_del函数让这个节点的前后节点
互相指向,然后再让这个节点的前后节点指向一个没有意义的地址
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值