C链表的2种构造方式

        记录下C语言中链表数据结构的2种使用模式。

一、数据和指针域混合

        数据域和指针域定义在同一个结构体定义中,C语言中没有模板,意味着一个代码工程有多少数据结构就需要多少对链表的.c和.h,事实上这样会导致很多的冗余代码。

头文件 list.h
#include<stdio.h>typedef struct node
{DATATYPE data;    //数据域struct node *next;    //指针域
}node;typedef struct list
{node *first;    //指向头节点node *last;     //指向尾节点(该成员可以要可以不要)int size;
};//初始化单链表
void init_list(list *list);
//尾部新增数据node
void push_back(list *list, DATATYPE buf);
//头部新增数据node
void push_front(list *list, DATATYPE buf);
//打印链表数据结构
void show_list(list *list);
//尾部删除数据node
void pop_back(list *list, DATATYPE buf);
//头部删除数据node
void pop_front(list *list, DATATYPE buf);
//获取链表数据深度
int length(list *list);
//清空链表数据结构
void clear(list *list);
//销毁链表
void destroy(list *list);
接口文件 list.c
#include "list.h"
#include <stdio.h>//初始化链表,head结点不计入size,且数据域无值
void init_list(list *list)
{list->first = list->last = (node *)malloc(sizeof(node));assert(NULL != list->first);//为head节点赋NULL初始值list->first->next = NULL;list->size = 0;
}//尾插,存入新结点数据
void push_back(list *list, DATATYPE buf)
{//创建尾插节点node *s = (node *)malloc(sizeof(node));assert(NULL != s);s->data = buf;    //根据数据结构DATATYPE做相应处理s->next = NULL;//将尾插节点连接到链表尾部list->last-next = s;//更改管理节点中last的指向;list->last = s;//更改有效节点的个数list->size++;
}//头插,存入新节点数据
void push_front(list *list, DATATYPE buf)
{node *s = (node *)malloc(sizeof(node));assert(NULL != s);s-data = buf;s-next = list->first->next;list->first->next = s;//如果是链表的第一个有效节点,需要改变尾指针的指向if(list->size == 0){list->last = s;}//更改有效节点的个数list->size++;
}//尾删,取出结点数据
void pop_back(list *list, DATATYPE* buf)
{//链表中是否还有结点if(list->size == 0)return ;//寻找倒数第二个结点node *p = list->first;while(p->next != list->last)p = p->next;//取出尾部节点数据buf = p->next->data;//删除尾部结点free(p->next);//更改尾指针的指向list->last = p;//更改现尾结点的指针域list->last->next = NULL;list->size --;
}//头删,取出结点数据
void pop_front(list *list, DATATYPE* buf)
{//链表中是否有元素?if(list->size == 0)return;//临时保存要删除结点的地址Node *p = list->first->next;//删除该结点与链表的连接list->first->next = p->next;//取出头节点数据buf = p;//删除结点free(p);//该链表是否只有一个有效结点if(list->size == 1){//更改尾指针的指向list->last = list->first;}//更改有效结点个数list->size--;
}

二、数据和指针域分离

        数据域与指针域分离是Linux内核的写法,非常有特点,抽象了链表中共性的指针操作,让使用者只需要关注自己的数据域。

头文件list_common.h

只构造小结构体 list 相关的宏或则接口,该部分是共用的只需要一份;

2024-04-01 实践记录//遍历链表,typeof内建函数在vc下无法编译,不确定什么原因
#define offsetof(type, memb) (unsigned long)(&((type *)0)->memb)
#define container_of(ptr, type, member) ({          \const typeof(((type *)0)->member)*__mptr = (ptr);    \(type *)((char *)__mptr - offsetof(type, member)); })//以pos遍历以head为头的链表
#define list_for_each(pos, head) \for (pos = (head)->next; pos != (head); pos = pos->next)
#define list_for_each_entry(pos, head, member)				\for (pos = container_of((head)->next, typeof(*pos), member);		\&pos->member != (head);					\pos = container_of(pos->member.next, typeof(*pos), member))//定义一个双向链表
struct list_head {struct list_head *next, *prev;
};
//初始化链表
static inline void
INIT_LIST_HEAD(struct list_head *list)
{list->next = list->prev = list;
}//链表操作
static inline void
__list_add(struct list_head *entry,struct list_head *prev, struct list_head *next)
{next->prev = entry;entry->next = next;entry->prev = prev;prev->next = entry;
}//在head之后插入节点
static inline void
list_add(struct list_head *entry, struct list_head *head)
{__list_add(entry, head, head->next);
}//在尾部添加节点
static inline void
list_add_tail(struct list_head *entry, struct list_head *head)
{__list_add(entry, head->prev, head);
}//删除链表结点
static inline void __list_del(struct list_head * prev, struct list head* next)
{next->prev = prev;prev->next = next;
}static inline void list_del(struct list_head *entry)
{__list_del(entry->prev, entry->next);entry->next = (void *) 0;entry->prev = (void *) 0;
}
头文件xxx_list.h

构造大结构体的数据结构和接口,与具体的数据结构相关,需要定义多份;

struct test_str {int val;struct list_head list;
};

接口文件xxx_list.c

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/785355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【解決|三方工具】Obi Rope 编辑器运行即崩溃问题

开发平台&#xff1a;Unity 2021.3.7 三方工具&#xff1a;Unity资产工具 - Obi Rope   问题背景 使用Unity三方开发工具 - Obi Rope 模拟绳索效果。配置后运行 Unity 出现报错并崩溃。通过崩溃日志反馈得到如下图所示 这是一个序列化问题造成的崩溃&#xff0c;指向性为 Obi…

基于8086数码管数字钟计时器设计

**单片机设计介绍&#xff0c;基于8086数码管数字钟计时器设计 文章目录 一 概要二、功能设计三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于8086数码管数字钟计时器设计是一个结合了微处理器控制、数码管显示以及计时功能的综合性项目。通过此设计&#xff0c;我们…

容器: list

1.list的使用(对比vector) 新增接口push_front(), pop_front() 2.vector的简单实现 成员变量 node* head 迭代器的实现(主要) 思想: 封装类, 模拟指针行为->的重载: 针对自定义类型, 通过其访问其中属性const迭代器: 模板的使用 问题 erase后迭代器失效, 更新迭代器…

(负载点电源)18V/2A同步降压芯片快速瞬态响应逐周期限流保护

1. 产品特性 ➢ 输入电压范围&#xff1a; 4.5V~18V ➢ 最大负载&#xff1a; 2A ➢ 内部 PWM 控制器以达到快速瞬时响应 ➢ 软启保护时间 tss&#xff1a; 1ms ➢ 逐周期限流保护 ➢ 内部补偿 ➢ 可调的输入欠压锁定 ➢ 短路保护&#xff0c;过温保护 2. 功能描述 P…

前端-css-01

1.CSS 长度单位和颜色设置 1.1CSS 中的长度单位 px 像素 em 字体大小的倍数&#xff08;字体默认是16px&#xff09; % 百分比 1.2CSS 中的颜色设置方式 1.2.1使用颜色名表示颜色 red、orange、yellow、green、cyan、blue、purple、pink、deeppink、skyblue、greenyellow .…

【漏洞复现】通天星CMSV6弱口令漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

机器学习-生存分析:基于QHScrnomo模型的乳腺癌患者风险评估与个性化预测

一、引言 乳腺癌作为女性常见的恶性肿瘤之一&#xff0c;对女性健康构成威胁。随着医疗技术的不断进步&#xff0c;个性化医疗逐渐成为乳腺癌治疗的重要方向。通过深入研究乳腺癌患者的风险评估和个性化预测&#xff0c;可以帮助医生更准确地制定治疗方案&#xff0c;提高治疗效…

篇二.软件需求管理办法

二、软件需求管理办法 第1章 总则 第1条 目的。 为使软件产品满足规定的需求而确定软件的体系结构、组成模块划分和接口说明等&#xff0c;并将上述结果翻译成代码&#xff0c;以实现软件所要求的功能&#xff0c;确保软件项目的顺利实施和高质量交付&#xff0c;特制定的软件…

人工智能中的数学计算和数学思想

1.人工智能中的数学计算 在人工智能&#xff08;AI&#xff09;领域&#xff0c;数学计算扮演着至关重要的角色&#xff0c;支撑着众多算法的设计与实现。以下是一些人工智能中常见的数学计算&#xff1a; 线性代数&#xff1a; 向量和矩阵运算&#xff1a;用于表示和处理高维…

强制不换行,

white-space:nowrap强制不换行&#xff0c;效果如下

NC21302 被3整除的子序列

题目描述 给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除 答案对1e97取模 输入描述: 输入一个字符串&#xff0c;由数字构成&#xff0c;长度小于等于50 输出描述: 输出一个整数 示例1 输入 132 输出 3 示例2 输入 9 输出 1 示例3 输入 …

[Java面试题]Java字符串比较面试题详解

字符串比较 通过字面量赋值创建字符串&#xff08;如&#xff1a;String s”hi”&#xff09;&#xff0c;会先在常量池中查找是否存在相同的字符串&#xff0c;若存在&#xff0c;则直接指向该字符串&#xff1b;若不存在&#xff0c;则在常量池中生成一个字符串&#xff0c;再…

FebHost:荷兰.NL域名一个富有影响力域名

作为荷兰的国家顶级域名,.NL域名可以说是荷兰互联网发展史上的一个重要里程碑。早在1986年,这个国家域名就已经正式推出,见证了荷兰从互联网新手到如今科技强国地位的转变。 时至今日,.NL域名在全球范围内已经享有广泛知名度。根据统计,截至2023年8月,已经注册的.NL域名数量高…

使用poco结构体转json

c结构体直接转成json字符串&#xff0c;代码示例 main.cpp #include <iostream> #include "global.h" #include "client_param.h" #include "md5.h" #include "common_func.h"using namespace std; using namespace demo;int ma…

vulhub打靶记录——driftingbox

文章目录 主机发现端口扫描目录扫描爆破子域名提权总结 主机发现 使用nmap扫描局域网内存活的主机&#xff0c;命令如下&#xff1a; nmap -sP 192.168.56.0/24192.168.56.1&#xff1a;主机IP&#xff1b;192.168.56.100&#xff1a;DHCP服务器IP&#xff1b;192.168.56.101…

轻松安装Kibana on Linux:手把手教你配置与说明

Kibana作为Elastic Stack的重要组成部分&#xff0c;为用户提供了一种直观、交互的方式来探索、分析和可视化Elasticsearch中的数据。本篇文章将引导您在Linux系统上轻松安装Kibana&#xff0c;并详细解说配置过程&#xff0c;确保即使是初学者也能快速上手。 一、安装Kibana …

`require`与`import`的区别

require与import的区别主要体现在以下几个方面&#xff1a; 1.加载时间不同。require是在运行时加载模块&#xff0c;这意味着模块的加载和执行可以在代码的任何地方进行&#xff0c;也可以在运行时根据条件动态地加载不同的模块&#xff1b;import是在编译时加载模块&#xf…

每日面经分享(pytest装饰器)

pytest装饰器 a. pytest.mark.parametrize&#xff1a;这个装饰器用于标记测试函数&#xff0c;并为其提供多组参数进行参数化测试。可以使用元组、列表、字典等形式来指定参数组合。 import pytestpytest.mark.parametrize("num1, num2, expected", [(2, 2, 4), (5…

2024年美团笔试题(1)

一.题目描述 小美拿到了一个排列&#xff0c;其中初始所有元素都是红色&#xff0c;但有些元素被染成了白色。 小美每次操作可以选择交换任意两个红色元素的位置。她希望操作尽可能少的次数使得数组变成非降序&#xff0c;你能帮帮她吗? 排列是指:一个长度为n的数组&#…

反编译winform程序的dll步骤

1、窗体文件还原 这块一开始我是参照正常窗体需要的文件格式去挨个还原的,即一个窗体有一个.cs文件,一个.Designer.cs文件,一个.resx文件。反编译后的文件是将前两个合到一个文件里了,资源文件是一个.resources文件,即一个.cs文件,一个.resources文件,而这个资源文件vs…