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

FreeRTOS 链表 从零到精通

第一步什么是链表链表 一串用指针连起来的结构体结构节点1 → 节点2 → 节点3 → NULL第二步链表节点结构体最核心struct Node { int data; // 存数据 struct Node *next; // 指向下一个节点关键 };- data随便存什么数据如数字、字符串- next存下一个节点的地址核心作用是将节点串联起来第三步创建3个节点并手动串联struct Node { int data; struct Node *next; }; ​ int main() { // 1. 创建3个节点 struct Node n1, n2, n3; ​ // 2. 给节点赋值 n1.data 10; n2.data 20; n3.data 30; ​ // 3. 手动串联节点 n1.next n2; // n1 指向 n2 n2.next n3; // n2 指向 n3 n3.next NULL; // 最后一个节点指向空标志链表结束 }最终链条n1 → n2 → n3 → NULL第四步链表遍历从头到尾读数据struct Node { int data; struct Node *next; }; ​ int main() { // 1. 创建并串联节点复用第三步代码 struct Node n1, n2, n3; n1.data 10; n2.data 20; n3.data 30; n1.next n2; n2.next n3; n3.next NULL; ​ // 2. 链表遍历核心用指针游走 struct Node *p n1; // 指针p从第一个节点开始 while(p ! NULL) { // 只要p不为空就继续往前走 printf(%d , p-data); // 读取当前节点数据 p p-next; // 指针往后挪一步指向 next 节点 } }运行输出结果10 20 30第五步动态创建节点malloc手动创建节点n1、n2、n3太麻烦用malloc动态开辟内存灵活创建节点#include stdio.h #include stdlib.h // malloc、free 所需头文件 ​ struct Node { int data; struct Node *next; }; ​ int main() { // 1. 动态申请3个节点内存代替手动定义n1、n2、n3 struct Node *n1 (struct Node*)malloc(sizeof(struct Node)); struct Node *n2 (struct Node*)malloc(sizeof(struct Node)); struct Node *n3 (struct Node*)malloc(sizeof(struct Node)); ​ // 2. 给节点赋值动态节点用 - 访问成员 n1-data 10; n2-data 20; n3-data 30; ​ // 3. 串联节点 n1-next n2; n2-next n3; n3-next NULL; ​ // 4. 遍历节点 struct Node *p n1; while(p ! NULL) { printf(%d , p-data); p p-next; } ​ // 5. 释放动态内存避免内存泄漏必写 free(n1); free(n2); free(n3); }第六步封装尾插函数自动加节点每次加节点都要写重复代码封装成函数一键添加节点#include stdio.h #include stdlib.h ​ // 1. 定义节点结构体 struct Node { int data; struct Node *next; }; ​ // 2. 全局头节点指针记录链表开头方便函数访问 struct Node *head NULL; ​ // 3. 尾插函数自动创建节点、自动串联到链表末尾 void addTail(int val) { // 3.1 新建一个节点 struct Node *newNode (struct Node*)malloc(sizeof(struct Node)); newNode-data val; // 给新节点赋值 newNode-next NULL; // 新节点默认是最后一个next指向空 ​ // 3.2 如果链表为空头节点为NULL新节点就是头节点 if(head NULL) { head newNode; return; } ​ // 3.3 如果链表不为空找到最后一个节点 struct Node *p head; while(p-next ! NULL) { // 走到next为NULL的节点最后一个 p p-next; } ​ // 3.4 把新节点连到最后一个节点后面 p-next newNode; } ​ int main() { // 4. 直接调用函数一键添加节点不用手动写串联代码 addTail(10); addTail(20); addTail(30); ​ // 5. 遍历链表 struct Node *p head; while(p ! NULL) { printf(%d , p-data); p p-next; } ​ // 6. 简易释放内存 while(head ! NULL) { struct Node *tmp head; head head-next; free(tmp); } }第七步FreeRTOS 链表结构双向 循环FreeRTOS 中的链表不用来存普通数据只用来管理任务排队、调度核心是「双向循环链表」// FreeRTOS 真实链表节点只有2个核心成员 struct ListItem { struct ListItem *next; // 下一个节点 struct ListItem *prev; // 上一个节点双向链表核心可往前、往后走 }; ​ // FreeRTOS 链表头管理整条链表 struct List { struct ListItem *next; // 指向链表第一个节点 struct ListItem *prev; // 指向链表最后一个节点 };核心特点1. 双向链表每个节点有 next后和 prev前可双向遍历2. 循环链表链表首尾相连没有 NULL 结尾3. 空链表状态链表头的 next 和 prev 都指向自己头 ↔ 头第八步FreeRTOS 链表初始化 插入实现 FreeRTOS 链表的核心操作初始化空链表、尾部插入节点#include stdio.h ​ // 1. FreeRTOS 链表结构不变 struct ListItem { struct ListItem *next; struct ListItem *prev; }; ​ struct List { struct ListItem *next; struct ListItem *prev; }; ​ // 2. 链表初始化FreeRTOS 官方逻辑 void vListInitialise(struct List *list) { // 空链表链表头的 next 和 prev 都指向自己 list-next (struct ListItem *)list; list-prev (struct ListItem *)list; } ​ // 3. 尾部插入节点FreeRTOS 核心插入逻辑 void vListInsertEnd(struct List *list, struct ListItem *newItem) { struct ListItem *listEnd (struct ListItem *)list; // 链表头当作链表结尾的标记 ​ // 核心4步将新节点插入到链表末尾头 ↔ 旧尾 ↔ 新尾 ↔ 头 newItem-next listEnd; // 新节点的 next 指向头循环 newItem-prev listEnd-prev; // 新节点的 prev 指向原来的最后一个节点 listEnd-prev-next newItem; // 原来最后一个节点的 next 指向新节点 listEnd-prev newItem; // 链表头的 prev 指向新节点新节点变成最后一个 } ​ // 4. 主函数测试 int main() { // 4.1 创建链表 初始化空链表头 ↔ 头 struct List list; vListInitialise(list); ​ // 4.2 创建2个节点任务节点 struct ListItem item1; struct ListItem item2; ​ // 4.3 插入节点到链表 vListInsertEnd(list, item1); vListInsertEnd(list, item2); ​ // 插入后链表状态头 ↔ item1 ↔ item2 ↔ 头 printf(FreeRTOS 链表初始化 插入完成\n); return 0; }第九步FreeRTOS 链表遍历新增遍历函数能直观看到链表中的所有节点验证插入是否成功#include stdio.h ​ // 1. FreeRTOS 链表结构不变 struct ListItem { struct ListItem *next; struct ListItem *prev; }; ​ struct List { struct ListItem *next; struct ListItem *prev; }; ​ // 2. 链表初始化不变 void vListInitialise(struct List *list) { list-next (struct ListItem *)list; list-prev (struct ListItem *)list; } ​ // 3. 尾部插入不变 void vListInsertEnd(struct List *list, struct ListItem *newItem) { struct ListItem *listEnd (struct ListItem *)list; ​ newItem-next listEnd; newItem-prev listEnd-prev; listEnd-prev-next newItem; listEnd-prev newItem; } ​ // 4. 新增遍历链表核心走到头就停止 void vListShow(struct List *list) { struct ListItem *p list-next; // 从第一个节点开始跳过链表头 printf(遍历链表); ​ // 循环终止条件指针回到链表头循环链表的特点 while( p ! (struct ListItem *)list ) { printf(节点地址%p , p); // 打印节点地址验证节点存在 p p-next; // 指针往后走一步 } ​ printf(\n); } ​ // 5. 主函数测试 int main() { // 5.1 初始化链表 struct List list; vListInitialise(list); ​ // 5.2 创建3个节点 struct ListItem item1; struct ListItem item2; struct ListItem item3; ​ // 5.3 插入节点 vListInsertEnd(list, item1); vListInsertEnd(list, item2); vListInsertEnd(list, item3); ​ // 5.4 遍历链表查看结果 vListShow(list); ​ return 0; }运行输出示例地址因人而异遍历链表节点地址0061FF18 节点地址0061FF14 节点地址0061FF10第十步FreeRTOS 官方完整版链表最终版加入 FreeRTOS 真实源码中的核心成员任务优先级、节点数量、所属任务完全复刻官方逻辑#include stdio.h ​ // // FreeRTOS 官方最终版链表结构真实源码简化版 // struct ListItem { struct ListItem *next; // 下一个节点 struct ListItem *prev; // 上一个节点 int itemValue; // 新增任务优先级 / 超时时间FreeRTOS 必加 void *pvOwner; // 新增该节点属于哪个任务指向任务结构体 }; ​ struct List { struct ListItem *next; // 指向第一个节点 struct ListItem *prev; // 指向最后一个节点 int len; // 新增链表节点数量方便管理任务数 }; ​ // // 1. 链表初始化官方逻辑 // void vListInitialise(struct List *list) { list-next (struct ListItem *)list; list-prev (struct ListItem *)list; list-len 0; // 初始节点数为0空链表 } ​ // // 2. 节点初始化官方逻辑给节点赋初始值 // void vListInitialiseItem(struct ListItem *item) { item-next NULL; item-prev NULL; item-itemValue 0; // 初始优先级为0 item-pvOwner NULL; // 初始无所属任务 } ​ // // 3. 尾部插入官方逻辑新增节点计数 // void vListInsertEnd(struct List *list, struct ListItem *newItem) { struct ListItem *listEnd (struct ListItem *)list; ​ newItem-next listEnd; newItem-prev listEnd-prev; ​ listEnd-prev-next newItem; listEnd-prev newItem; ​ list-len; // 插入节点后链表长度1 } ​ // // 4. 遍历链表优化版显示优先级 // void vListShow(struct List *list) { struct ListItem *p list-next; printf(链表长度%d | 节点优先级, list-len); ​ while(p ! (struct ListItem *)list) { printf([%d] → , p-itemValue); // 打印任务优先级 p p-next; } printf(头循环结束\n); } ​ // // 5. 主函数最终测试模拟FreeRTOS任务管理 // int main() { // 5.1 初始化链表任务链表 struct List taskList; vListInitialise(taskList); ​ // 5.2 创建3个任务节点模拟3个任务 struct ListItem task1, task2, task3; vListInitialiseItem(task1); vListInitialiseItem(task2); vListInitialiseItem(task3); ​ // 5.3 给3个任务设置不同优先级数值越大优先级越高 task1.itemValue 1; // 任务1优先级1 task2.itemValue 2; // 任务2优先级2 task3.itemValue 3; // 任务3优先级3 ​ // 5.4 将任务节点插入链表模拟任务排队 vListInsertEnd(taskList, task1); vListInsertEnd(taskList, task2); vListInsertEnd(taskList, task3); ​ // 5.5 遍历链表查看任务排队情况 vListShow(taskList); ​ return 0; }运行输出结果链表长度3 | 节点优先级[1] → [2] → [3] → 头循环结束总结你已完全掌握 FreeRTOS 链表✅ 核心基础结构体 指针串联✅ 链表类型双向循环链表FreeRTOS 核心✅ 核心操作初始化、插入、遍历✅ 官方特性任务优先级、节点计数、所属任务⚠️ 注意FreeRTOS 链表的核心用途是「任务管理」用于任务排队、延时调度、队列/信号量底层实现这是 FreeRTOS 内核的核心基石。

相关文章:

FreeRTOS 链表 从零到精通

第一步:什么是链表?链表 一串用 指针 连起来的结构体结构:节点1 → 节点2 → 节点3 → NULL第二步:链表节点结构体(最核心)struct Node {int data; // 存数据struct Node *next; // 指向下一个…...

3步高效解锁智慧树自动化学习:技术原理解析与实战指南

3步高效解锁智慧树自动化学习:技术原理解析与实战指南 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 你是否厌倦了在智慧树平台上重复点击下一集、手动调节…...

Claude Code 配置教程

Claude Code 是由 Anthropic 推出的编程代理,能够在多种环境中使用,例如终端、集成开发环境(IDE)以及桌面应用程序。通过使用 AceData Cloud 代理,您可以以更低的成本使用 Claude Code。这篇文章将为您提供不同平台的配…...

iOS 17-26越狱完整指南:安全解锁iPhone隐藏功能

iOS 17-26越狱完整指南:安全解锁iPhone隐藏功能 【免费下载链接】Jailbreak iOS 26.4 - 26, 17 - 17.7.5 & iOS 18 - 18.7.3 Jailbreak Tools, Cydia/Sileo/Zebra Tweaks & Jailbreak News Updates || AI Jailbreak Finder 👇 项目地址: https…...

别再手动点鼠标了!用这个Praat脚本批量提取音频时长和F1F2共振峰(附Excel作图教程)

语音数据分析自动化:用Praat脚本高效提取时长与共振峰 每次打开Praat软件,面对几十个甚至上百个音频文件时,你是否感到手指发酸?那些重复点击"Analyse"→"Formant"→"To Formant"的操作&#xff0c…...

SpringBoot项目里,如何优雅地集成ip2region实现离线IP定位(附完整工具类)

SpringBoot深度整合ip2region:构建高并发离线IP定位服务实战 当我们需要在电商平台分析用户地域分布、在内容平台实现地区化推荐、在风控系统中识别异常登录时,IP定位往往是第一个技术抓手。而ip2region这个不足10MB的离线库,却能提供99.9%准…...

解放双手的终极指南:如何用MAA自动化助手轻松管理《明日方舟》日常任务

解放双手的终极指南:如何用MAA自动化助手轻松管理《明日方舟》日常任务 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手,全日常一键长草!| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地…...

golang如何使用SQLx原生SQL查询_golang SQLx原生SQL查询使用方法

SQLx查单行必须用Get而非QueryRow,以启用StructScan;Exec仅用于无结果集的增删改,RETURNING需配Get/Select;命名参数仅PostgreSQL原生支持,MySQL/SQLite需用位置参数或Rebind。SQLx 查询单行数据用 Get,别用…...

终极5个驱动清理技巧:如何用DriverStore Explorer释放Windows磁盘空间

终极5个驱动清理技巧:如何用DriverStore Explorer释放Windows磁盘空间 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 您的C盘是否经常空间不足?系统运行越来越慢…...

为什么你需要一个启动器来统一管理所有二次元游戏模组?

为什么你需要一个启动器来统一管理所有二次元游戏模组? 【免费下载链接】XXMI-Launcher Modding platform for GI, HSR, WW and ZZZ 项目地址: https://gitcode.com/gh_mirrors/xx/XXMI-Launcher 你是否曾经为了给不同的二次元游戏安装模组,需要在…...

如何用Lenovo Legion Toolkit完全掌控你的联想拯救者笔记本:开源硬件管理终极指南

如何用Lenovo Legion Toolkit完全掌控你的联想拯救者笔记本:开源硬件管理终极指南 【免费下载链接】LenovoLegionToolkit Lightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops. 项目地址: https://gitcode.com/gh_mirrors/le/LenovoLe…...

ViGEmBus:Windows终极虚拟手柄驱动完全指南

ViGEmBus:Windows终极虚拟手柄驱动完全指南 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 想要在Windows系统上完美模拟Xbox 360和DualShock 4游…...

NVIDIA Profile Inspector深度指南:解锁NVIDIA显卡隐藏配置的完整实战方法

NVIDIA Profile Inspector深度指南:解锁NVIDIA显卡隐藏配置的完整实战方法 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector NVIDIA Profile Inspector是一款强大的开源工具,专为N…...

Phi-4-reasoning-vision-15B应用场景:法律文书截图→当事人/案由/判决结果三要素抽取

Phi-4-reasoning-vision-15B在法律文书分析中的应用:三要素智能抽取实践 1. 法律文书处理的痛点与解决方案 法律从业者每天需要处理大量裁判文书、合同协议等法律文件。传统的人工阅读和提取关键信息的方式存在效率低下、容易遗漏等问题。以一份典型的法院判决书为…...

MySQL从库出现数据同步异常中断_重新获取binlog坐标同步

SHOW SLAVE STATUS中Seconds_Behind_Master为NULL且IO/SQL线程为No,表明复制已中断而非延迟;需据Last_IO_Error或Last_SQL_Error类型采取对应措施:网络问题查连通性,SQL错误需确认数据一致性,binlog缺失则需重设坐标&a…...

Stable Yogi Leather-Dress-Collection生成控制进阶:使用ControlNet精确约束服饰轮廓

Stable Yogi Leather-Dress-Collection生成控制进阶:使用ControlNet精确约束服饰轮廓 每次看到那些设计感十足的皮革连衣裙,我都会想,如果能把自己的草图直接变成高清效果图该多好。以前用AI生成图片,总像是在开盲盒——输入一段…...

什么是补丁更新的“双缓冲区”?深度探讨虚拟 DOM 的状态同步机制

“补丁更新的双缓冲区”是类比图形学双缓冲对虚拟DOM状态隔离与原子切换机制的描述:旧新虚拟DOM结构分离、diff延迟应用、更新具原子性,并借异步调度解耦计算与渲染。“补丁更新的双缓冲区”并不是一个标准术语,它其实是对虚拟 DOM 更新过程中…...

PHP源码运行需要多少U高度机架_服务器安装空间说明【指南】

PHP本身不占用机架U高度,它是运行在服务器操作系统上的解释型脚本语言,实际U数取决于承载其运行环境的物理或虚拟硬件载体。PHP 本身不占用机架 U 高度——它跑在服务器操作系统上,不是硬件设备。你买的是运行 PHP 的服务器,不是“…...

SpringBoot+Vue自习室座位预约系统源码+论文

代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹 分享万套开题报告任务书答辩PPT模板 作者完整代码目录供你选择: 《SpringBoot网站项目》1800套 《SSM网站项目》1500套 《小程序项目》1600套 《APP项目》1500套 《Python网站项目》…...

CefFlashBrowser:解决Flash内容访问与存档管理的完整解决方案

CefFlashBrowser:解决Flash内容访问与存档管理的完整解决方案 【免费下载链接】CefFlashBrowser Flash浏览器 / Flash Browser 项目地址: https://gitcode.com/gh_mirrors/ce/CefFlashBrowser 你是否还在为无法在现代浏览器中运行经典Flash游戏而烦恼&#x…...

VBA-JSON实战指南:在Office中快速实现JSON数据处理的完整方案

VBA-JSON实战指南:在Office中快速实现JSON数据处理的完整方案 【免费下载链接】VBA-JSON JSON conversion and parsing for VBA 项目地址: https://gitcode.com/gh_mirrors/vb/VBA-JSON VBA-JSON是一款专为Microsoft Office环境设计的JSON解析库,…...

终极动物森友会存档编辑器:NHSE完全指南与3步快速上手教程

终极动物森友会存档编辑器:NHSE完全指南与3步快速上手教程 【免费下载链接】NHSE Animal Crossing: New Horizons save editor 项目地址: https://gitcode.com/gh_mirrors/nh/NHSE 你是否厌倦了在动物森友会中花费数小时收集稀有物品?是否梦想着能…...

Vue 3 组合式 API 到底香在哪?

Vue 3 组合式 API 到底香在哪? 近年来,Vue 3 的组合式 API(Composition API)成为前端开发者的热门话题。相较于 Vue 2 的选项式 API,组合式 API 提供了更灵活、更高效的代码组织方式。那么,它究竟“香”在…...

绝地求生罗技鼠标宏:告别手抖,精准压枪的终极指南

绝地求生罗技鼠标宏:告别手抖,精准压枪的终极指南 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 还在为PUBG中难以控制的…...

告别官方模板:手把手教你为ESP32定制LVGL工程,适配任意SPI屏幕驱动

告别官方模板:手把手教你为ESP32定制LVGL工程,适配任意SPI屏幕驱动 在嵌入式GUI开发领域,LVGL凭借其轻量级和高度可定制的特性,已成为ESP32项目的热门选择。但当你从官方示例转向实际项目时,往往会遇到一个现实问题&am…...

从‘纳什均衡’到‘模式崩溃’:聊聊GAN训练中那些loss曲线告诉你的故事(附TensorFlow 2.x诊断技巧)

从‘纳什均衡’到‘模式崩溃’:解码GAN训练中的损失曲线玄机 当你盯着GAN训练过程中那些跳动的损失曲线时,是否曾感到困惑——为什么判别器的损失突然跌到零?为什么生成器的指标像过山车一样起伏不定?这些曲线背后隐藏着生成对抗网…...

Vivado TCL脚本进阶:把JTAG to AXI Master IP变成你的自动化调试神器

Vivado TCL脚本进阶:把JTAG to AXI Master IP变成你的自动化调试神器 在FPGA开发的世界里,调试效率往往决定着项目成败。当传统手动操作遇到复杂状态机验证或批量寄存器测试时,工程师们常常陷入重复劳动的泥潭。而Xilinx Vivado中那颗被低估的…...

LiuJuan20260223Zimage与STM32开发联动:嵌入式AI应用生成案例

LiuJuan20260223Zimage与STM32开发联动:嵌入式AI应用生成案例 最近在折腾一个基于STM32的智能环境监测项目,从传感器数据采集到通过Wi-Fi上报云端,整个过程涉及不少代码编写和调试。就在我对着数据手册和参考例程,一行行敲着ADC初…...

避坑指南:STM32连接ADS1256时SPI时序与DRDY引脚的那些事儿

STM32与ADS1256高效通信实战:SPI时序优化与DRDY引脚深度解析 调试ADS1256这类高精度ADC时,工程师们常会遇到数据不稳定、通信失败等"玄学问题"。上周深夜,当我第三次抓取到杂乱的SPI波形时,才意识到数据手册里那些微妙…...

Unity项目避坑指南:从零配置Plastic SCM到多人协作(含YAML合并工具设置)

Unity项目避坑指南:从零配置Plastic SCM到多人协作(含YAML合并工具设置) 第一次接触Plastic SCM的Unity开发者,往往会在配置过程中踩遍所有能想到的坑。从安装路径的选择到YAML合并工具的配置,每一步都可能隐藏着让项…...