c语言内核链表
在Linux中拥有大量的内核源码,在数据存储的这块位置拥有内核链表(双向循环链表)
由linux内核提供的链表文件,里面包含了多组内联函数和宏定义函数以及功能性函数。
内核链表中定义了多个函数,我们只需要知道参数的类型,然后填入参数,即可完成增删改查操作。
内核链表兼容了通用性,将指针域剥离出来,只封装指针域来管理节点。
内核链表优缺点:
优点:逻辑完整,函数封装完整,只需要调用,指针域独立管理节点。
缺点:用户无法修改内核链表的写法。
实现内核链表的使用
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
typedef struct node
{
int data; // 数据域
// 小结构体 这里为什么最好不用指针是因为内核函数里面有一个参数是取名字,并且初始化的时候取得是名字的地址&(name)
struct list_head xNode;
} DNode, *DNODE;
// 初始化头结点
DNODE initHead()
{
// 申请空间
DNODE Dhead = malloc(sizeof(DNode));
if (Dhead == NULL)
{
printf("大结构体空间申请失败!\n");
return NULL;
}
// 初始化指针域
INIT_LIST_HEAD(&(Dhead->xNode));
return Dhead;
}
// 初始化普通节点
DNODE initNode(int data)
{
// 申请空间
DNODE xNode = malloc(sizeof(DNode));
if (xNode == NULL)
{
printf("小结构体空间申请失败!\n");
return NULL;
}
// 初始化数据域
xNode->data = data;
// 初始化指针域
INIT_LIST_HEAD(&(xNode->xNode));
return xNode;
}
// 插入节点
void insertNode(DNODE Dhead, DNODE xnode)
{
// 插入头节点之前
// list_add(&(xnode->xNode), &(Dhead->xNode));
// 插入头节点之后
list_add_tail(&(xnode->xNode), &(Dhead->xNode));
}
// 遍历链表
void showList(DNODE Dhead)
{
// 两种写法遍历链表
struct list_head *pos, *safe_pos; // 小结构体指针
DNODE safe_node, node; // 大结构体指针
printf("head->");
// 正向遍历 list_for_each
// list_for_each(pos, &(Dhead->xNode))
// 逆向遍历 list_for_each_prev
// list_for_each_prev(pos, &(Dhead->xNode))
// 正向安全遍历
// list_for_each_safe(pos, safe_pos, &(Dhead->xNode))
// // 逆向安全遍历
// // list_for_each_prev_safe(pos, safe_node, &(Dhead->xNode))
// {
// /*
// * 通过list_entry方法放入小结构体地址获取到大结构体地址
// * pos小结构体地址
// * DNode大结构体类型
// * xNode小结构体名字
// */
// DNODE newName = list_entry(pos, DNode, xNode);
// printf("%d->", newName->data);
// }
/**
* 而安全跟不安全的区别就是,不安全的不支持遍历删除,如果在循环内部删除了当前节点,可能会导致遍历指针 (pos) 指向一个已经被删除的节点,从而引发未定义行为。
* 上下两种遍历方式区别
* 跟上面正向的却别就是上面方法需要通过小结构体找到大结构体再通过大结构体访问数据
* 而下面这种方法遍历访问数据直接就通过大结构体访问
*/
// 大结构体正向遍历
// list_for_each_entry(safe_node, &(Dhead->xNode), xNode)
// 正向安全
list_for_each_entry_safe(safe_node, node, &(Dhead->xNode), xNode)
{
/*
* 通过list_entry方法放入小结构体地址获取到大结构体地址
* pos小结构体地址
* DNode大结构体类型
* safe_node 大结构体节点
*/
printf("%d->", safe_node->data);
}
printf("\n");
}
// 删除节点
void del_node(DNODE Dhead, int data)
{
// 赋初始值为头结点地址
DNODE pos = Dhead;
// 找到符合条件的大结构体节点
list_for_each_entry(pos, &(Dhead->xNode), xNode)
{
if (pos->data == data)
break;
}
// if (pos != Dhead)
// 如果链表非空
if (!list_empty(&(pos->xNode)))
{