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 内核的核心基石。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2535937.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!