当前位置: 首页 > news >正文

C-数据结构-双向链表(linux内核 )

/*
借用list.h内核源码 实现双向链表
list.h解析 可参考

https://blog.csdn.net/u012351051/article/details/99193521

*/

lish.h

#ifndef LINUX_LIST_H__
#define LINUX_LIST_H__#define LIST_HEAD_INIT(name)	{&(name),&(name)}
#deinfe LIST_HEAD(name)	struct list_head name = LIST_HEAD_INIT(name)struct list_head
{struct list_head *prev;struct list_head *next;
}static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next)
{next->prev = new;new->next = next;new->prev = prev;prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{__list_add(new, head, head->next);
}
#define list_for_each(pos, head) \for (pos = (head)->next;  pos != (head); pos = pos->next)/* ptr->curtype->struct score_stmember->node
*/#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)#define container_of(ptr, type, member) ({			\const typeof(((type *)0)->member) * __mptr = (ptr);	\(type *)((char *)__mptr - offsetof(type, member)); })#define list_entry(ptr, type, member) \container_of(ptr, type, member)#endif

main.c

#include<stdio.h>
#include<stdlib.h>
#include "list.h"
#define NAMESIZE	32
struct score_st
{int id;char name[NAMESIZE];struct list_head node;//谁用这个链表 就把当前的结构包含进来int math;int chinese;
}
static void print_s(struct score_st *d)
{printf("%d %s %d %d\n",d->id,d->name,d->math,d->chinese);
}int main()
{int i;struct score_st *datap;struct list_head *cur;LIST_HEAD(head);for(i = 0;i<7 ;i++){datap = malloc(sizeof(*datap));if(datap == NULL)exit(1);datap->id = i;snprintf(datap->name,NAMESIZE,"stu%d",i);data->math = rand()%100;data->chinese = rand()%100;list_add(&datap->node,&head);}	list_for_each(cur,&head){datap = list_entry(cur,struct score_st,node);print_s(datap);}list_for_each(cur,&head){datap = list_entry(cur,struct score_st,node);if(datap->id= 5)break;}if(cur = &head)printf("can not find!\n");elseprint_s(datap);exit(0);
}

补充说明

LIST_HEAD(head) 是一个宏,它用于定义并初始化一个双向链表的头节点。在你的代码中,它的作用是创建并初始化一个名为 head 的链表头节点。让我们详细解释一下这个宏和它的作用。

解释 LIST_HEAD(head)

list.h 头文件中,LIST_HEAD 宏定义如下:

#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)

这个宏展开为以下代码:

struct list_head head = {&(head), &(head)};

这里 LIST_HEAD_INIT(name) 是一个初始化宏,它将链表头节点的 prevnext 指针都指向节点自身。这就意味着,head 既是链表的起点也是链表的终点,表示一个空的链表。

详细解析

  1. 定义链表头节点

    #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
    

    这个宏定义了一个 struct list_head 类型的变量,并使用 LIST_HEAD_INIT 宏初始化它。

  2. 初始化链表头节点

    #define LIST_HEAD_INIT(name) {&(name), &(name)}
    

    这个宏初始化链表头节点,使其 prevnext 都指向自己,表示一个空的双向链表。

使用示例

在你的 main.c 文件中,有以下代码:

LIST_HEAD(head);

这行代码等同于:

struct list_head head = {&head, &head};

这就创建了一个链表头节点 head,并且初始化了它的 prevnext 指针,使它们都指向 head 本身,表示链表为空。

如何工作

让我们看看这个链表头节点如何在代码中使用:

  1. 初始化链表

    LIST_HEAD(head);
    
  2. 向链表添加节点

    for (i = 0; i < 7; i++) {datap = malloc(sizeof(*datap));if (datap == NULL)exit(1);datap->id = i;snprintf(datap->name, NAMESIZE, "stu%d", i);datap->math = rand() % 100;datap->chinese = rand() % 100;list_add(&datap->node, &head);
    }
    
    • 这里我们通过 list_add 函数将新节点添加到链表中。
    • list_add 调用了 __list_add,它更新新节点和链表中其他节点的指针,使新节点正确插入链表。
  3. 遍历链表

    list_for_each(cur, &head) {datap = list_entry(cur, struct score_st, node);print_s(datap);
    }
    
    • 这里我们使用 list_for_each 宏遍历链表,从头节点开始,依次访问每个节点。

总结

LIST_HEAD(head) 的作用是定义并初始化一个链表头节点 head,表示一个空的双向链表。这个链表头节点的 prevnext 指针都指向自身。通过这种方式,可以方便地使用头节点来管理和操作双向链表中的所有节点。

相关文章:

  • 【linux系统学习教程 Day03】网络安全之Linux系统学习教程,用户和用户组管理,创建用户,删除用户,创建组,删除组....
  • (Oracle)SQL优化基础(三):看懂执行计划顺序
  • 官宣!正式成为淡人!向数据备份焦虑Say NO!
  • 三元组的最短距离
  • 【论文速读】|探索ChatGPT在软件安全应用中的局限性
  • ubuntu20.04 10分钟搭建无延迟大疆无人机多线程流媒体服务器
  • linux系统安全加固
  • URL化00
  • 适用于 Windows 7/8/10/11 的 6 款最佳免费分区软件
  • vue使用Less报错semi-colon expectedcss(css-semicolonexpected)的解决方法
  • Java高级面试精粹:问题与解答集锦(一)
  • 【MySQL精通之路】MySQL的使用(2)-配置
  • 如何快速申请免费单域名SSL证书
  • 基于xilinx fpga RFSOC系列的Ultrascale+ RF Data Converter ip详解说明
  • 【计算机网络原理】对传输层TCP协议的重点知识的总结
  • 【node学习】协程
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • 0基础学习移动端适配
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • Docker 笔记(2):Dockerfile
  • Hibernate最全面试题
  • Intervention/image 图片处理扩展包的安装和使用
  • Java 23种设计模式 之单例模式 7种实现方式
  • mongodb--安装和初步使用教程
  • Python学习笔记 字符串拼接
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • ReactNativeweexDeviceOne对比
  • tab.js分享及浏览器兼容性问题汇总
  • use Google search engine
  • Web Storage相关
  • XForms - 更强大的Form
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 排序(1):冒泡排序
  • 树莓派 - 使用须知
  • 一天一个设计模式之JS实现——适配器模式
  • 移动端唤起键盘时取消position:fixed定位
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 云大使推广中的常见热门问题
  • 进程与线程(三)——进程/线程间通信
  • ​ 轻量应用服务器:亚马逊云科技打造全球领先的云计算解决方案
  • ​无人机石油管道巡检方案新亮点:灵活准确又高效
  • ​香农与信息论三大定律
  • #考研#计算机文化知识1(局域网及网络互联)
  • (Note)C++中的继承方式
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • **python多态
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .NET 5种线程安全集合
  • .net 按比例显示图片的缩略图
  • .NET 快速重构概要1
  • .NET 同步与异步 之 原子操作和自旋锁(Interlocked、SpinLock)(九)
  • .net通用权限框架B/S (三)--MODEL层(2)