代码是最好的老师,本文以代码展示为主。
要想使用内核链表,就要在结构体中包含struct list_head
类型的变量,该变量将每个元素串联起来,构成一个双向链表。
struct list_head双向链表节点
struct list_head {
struct list_head *next;
struct list_head *prev;
};
链表头初始化:使用链表前,必须初始化链表头部
// 初始化链表头
#define INIT_LIST_HEAD(head) do { \
(head)->next = (head)->prev = head; \
} while (0)
插入
// 在head元素后面,插入new
1. 如果head是链表头,则: 头插
2. 如果head是元素,则:在元素后,插入new (将new插入到head后面)
static inline void
list_add (struct list_head *new, struct list_head *head)
{
new->prev = head;
new->next = head->next;
new->prev->next = new;
new->next->prev = new;
}
// 尾插:
1. 如果head是链表头,则:尾插
2. 如果head是元素,则:在元素前,插入new (将new插入到head前面)
static inline void
list_add_tail (struct list_head *new, struct list_head *head)
{
new->next = head;
new->prev = head->prev;
new->prev->next = new;
new->next->prev = new;
}
删除
// 删除链表中的节点(不要使用,比较危险,因为old没有prev/next没设置为NULL)
static inline void
list_del (struct list_head *old)
{
old->prev->next = old->next;
old->next->prev = old->prev;
old->next = (void *)0xbabebabe;
old->prev = (void *)0xcafecafe;
}
// 删除链表中的节点(推荐使用,安全)
static inline void
list_del_init (struct list_head *old)
{
old->prev->next = old->next;
old->next->prev = old->prev;
old->next = old;
old->prev = old;
}
移动move
// 将元素list从表中删除,头插入链表head中/将插入到head后面
static inline void
list_move (struct list_head *list, struct list_head *head)
{
list_del (list);
list_add (list, head);
}
// 将元素list从表中删除,尾插入链表head中/插入到head前面
static inline void
list_move_tail (struct list_head *list, struct list_head *head)
{
list_del (list);
list_add_tail (list, head);
}
链表判空
/**
* 判断链表是否为空
* @return 空,1;非空,0
*/
static inline int
list_empty (struct list_head *head)
{
return (head->next == head);
}
链表拼接
static inline void
__list_splice (struct list_head *list, struct list_head *head)
{
(list->prev)->next = (head->next);
(head->next)->prev = (list->prev);
(head)->next = (list->next);
(list->next)->prev = (head);
}
/*
拼接两个链表:
1.如果新增的链表只有一个链表头就不做任何处理(因为链表头不包含数据)
2. (head 2 3) + (add 5 6)
==> (head 5 6 2 3) //抛弃链表头add
*/
static inline void
list_splice (struct list_head *list, struct list_head *head)
{
if (list_empty (list))
return;
__list_splice (list, head);
}
/* Splice moves @list to the head of the list at @head. */
static inline void
list_splice_init (struct list_head *list, struct list_head *head)
{
if (list_empty (list))
return;
__list_splice (list, head);
INIT_LIST_HEAD (list);
}
/* Splice moves @list to the tail of the list at @head. */
static inline void
list_splice_tail_init (struct list_head *list, struct list_head *head)
{
if (list_empty (list))
return;
__list_splice (list, head->prev);
INIT_LIST_HEAD (list);
}
static inline void
__list_append (struct list_head *list, struct list_head *head)
{
(head->prev)->next = (list->next);
(list->next)->prev = (head->prev);
(head->prev) = (list->prev);
(list->prev)->next = head;
}
static inline void
list_append (struct list_head *list, struct list_head *head)
{
if (list_empty (list))
return;
__list_append (list, head);
}
/* Append moves @list to the end of @head */
static inline void
list_append_init (struct list_head *list, struct list_head *head)
{
if (list_empty (list))
return;
__list_append (list, head);
INIT_LIST_HEAD (list);
}
#define list_next(ptr, head, type, member) \
(((ptr)->member.next == head) ? NULL \
: list_entry((ptr)->member.next, type, member))
获取list所处对象的地址
/**
list_for_each(iter, &stu_list_head->list) {
stu_node = list_entry(iter, stu_list_t, list);
printf("id = %d, name = %s\n", stu_node->student->id, stu_node->student->name);
}
等价于 list_for_each_entry()
#define GET_LAST_NODE(set) \
list_entry(set.list.prev, typeof(df_file), slist)
*/
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
遍历链表
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/**
* 遍历(打印)链表
* @example
* stu_list_t* entry; // 必须是结构体类型
// lhead类型:struct list_head*
// list:是stu_list_t结构体中的struct list_head的member名字
list_for_each_entry(entry, lhead, list)
{
printf("id=%d, name=%s\n",entry->student->id, entry->student->name);
}
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
* 遍历(删除)链表
* @param [in] stu_list_t * pos 当前元素
* @param [in] stu_list_t * n
* @param [in] list_head* head 链表的头结点
* @param [in] member stu_list_t结构体中list成员名
* @example
stu_list_t* entry, * tmp; // 必须是结构体类型
// lhead类型:struct list_head*
// list:是stu_list_t结构体中的struct list_head的member名字
list_for_each_entry_safe(entry, tmp, lhead, list)
{
// 从链表中删除节点
list_del(&entry->list);
// 释放
free(entry->student);
free(entry);
}
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member))
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
n = list_entry(pos->member.prev, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
#endif /* _LLIST_H */
代码案例
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
typedef struct stu {
int id;
char name[10];
} stu_t;
typedef struct {
struct list_head list; // 简单理解,只要在struct中包含了struct list,该结构体就变成一个链表
stu_t *student; // 数据
} stu_list_t;
stu_list_t *new_stu(int i)
{
stu_list_t *stu_node = (stu_list_t *)malloc(sizeof(stu_list_t));
stu_node->student = (stu_t *)malloc(sizeof(stu_t));
stu_node->student->id = i;
sprintf(stu_node->student->name, "%d", i);
return stu_node;
}
// 遍历打印
void list_travel(struct list_head* lhead)
{
stu_list_t* entry;
list_for_each_entry(entry, lhead, list)
{
printf("id=%d, name=%s\n",entry->student->id, entry->student->name);
}
}
// 遍历删除
void list_free(struct list_head* lhead)
{
stu_list_t* entry, * tmp;
list_for_each_entry_safe(entry, tmp, lhead, list)
{
// 从链表中删除节点
list_del(&entry->list);
// 释放
free(entry->student);
free(entry);
}
}
int main()
{
struct list_head lhead;
// 初始化链表
INIT_LIST_HEAD(&lhead);
// 创建学生节点,插入链表lhead
int i;
for (i = 0; i < 5; i++) {
// 创建学生节点
stu_list_t *stu_node = new_stu(i);
// 将学生节点,插入到链表中
list_add(&stu_node->list, &lhead); // 头插
}
list_travel(&lhead);
printf("empty = %d\n", list_empty(&lhead)); // 0 表示不空
list_free(&lhead);
printf("empty = %d\n", list_empty(&lhead)); // 1 表示空
list_travel(&lhead);
return 0;
}
问题
代码中,出现 struct list_head list;
,此处的 list
表示什么含义呢?
此处有2层含义:
① 在结构体中,仅仅表示该结构体能够通过list这个member,连接成一个链表
注意:该成员不需要初始化。 将结构体插入链表,本质上是将结构体中的list成员插入链表
typedef struct {
int sno;
struct list_head list; // 表示node_t节点可以通过list构成一个链表
} node_t;
int main()
{
struct list_head lhead; // 作为链表头,表示一个链表
INIT_LIST_HEAD(&lhead);
node_t nd;
nd.sno = 100;
// nd.list不用初始化
list_add(&nd.list, &lhead);
}
② 作为链表头,表示一个链表
注意:必须被初始化。 可以将结构体插入到该链表
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
typedef struct {
int sno;
struct list_head list; // 表示node_t节点可以通过list构成一个链表
} node_t;
typedef struct {
int node_cnt;
struct list_head nodes_hd; // 作为链表头,表示一个链表
} bignode_t;
int main()
{
// 1.初始化bignode_t
bignode_t *bnd = malloc(sizeof(bignode_t));
bnd->node_cnt = 0;
INIT_LIST_HEAD(&bnd->nodes_hd);
// 2.创建node_t节点
node_t *nd = malloc(sizeof(nd));
nd->sno = 1008611;
// 3.将nd插入到链表nodes_hd中
list_add(&nd->list, &bnd->nodes_hd);
bnd->node_cnt++;
}
① ② 代码综合案例
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
typedef struct {
int sno;
struct list_head list; // 表示node_t节点可以通过list构成一个链表
} node_t;
typedef struct {
int node_cnt;
struct list_head list; // 表示bignode_t节点可以通过list构成一个链表
struct list_head nodes_hd; // 表示链表头(在此处,该链表元素类型是node_t)
} bignode_t;
int main()
{
// 1.初始化bignode_t
bignode_t *bnd = malloc(sizeof(bignode_t));
bnd->node_cnt = 0;
INIT_LIST_HEAD(&bnd->nodes_hd);
// 2.创建node_t节点
node_t *nd = malloc(sizeof(nd));
nd->sno = 1008611;
// 3.将nd插入到链表nodes_hd中
list_add(&nd->list, &bnd->nodes_hd);
bnd->node_cnt++;
struct list_head bignds_hd;
INIT_LIST_HEAD(&bignds_hd);
list_add(&bnd->list, &bignds_hd); // bnd又作为元素,插入到bignds_hd链表中
}