1898_野火FreeRTOS教程阅读笔记_链表操作

1898_野火FreeRTOS教程阅读笔记_链表操作

全部学习汇总: g_FreeRTOS: FreeRTOS学习笔记 (gitee.com)

新的节点的插入,影响到的是链表中最后一个元素的后继以及当前被插入元素的前驱、后继以及归属属性。具体的操作效果为:新的节点更新自己的前驱和后继,而对等的关联信息则是当前pxIndex所指向的前驱和链表的尾结点。而链表的尾结点在初始化的时候,pxIndex存储的其实是指向链表尾结点Item的指针。因此,这里的这个赋值更新,其实是实现了让这个新的节点指向了链表的尾节点。

这第一次用到了xItemValue的元素,其实这个元素的数值算是一个元素在链表上的位置的权重信息。如果这个数值很大,意味着需要插入到链表的最后。从效果上来讲,直接调用插入到End的接口也是可行的。这里相当于把对应逻辑重新写了一遍,但是从函数调用的资源消耗角度来说,这种写法应该效率高。插入的位置点寻找原则是从List的开头向后寻找,插入到数值小于等于自己的元素最后面。而最后的链表归属以及链表中元素个数的处理,与插入End其实是一回事儿。

对于这样的数据结构设计,链表节点的删除实现相当容易:

  • 前驱之后继为吾之后继
  • 后继之前驱为吾之前驱
  • 解脱list归属关系
  • 统计节点数目需要减1

代码中还增加了一个pxIndex的处理,这个也是围绕现在的数据结构所作的特殊处理。主要是考虑到移除的节点是List最后一个节点的情况。

关于链表的测试部分可以有很多,这个教程中用到的不是很多。针对这个仿真工具我了解不多,因此除了Memory的查看之外我额外增加了辅助显示的测试代码。

上面是我修改之后的测试代码,增加了一个辅助查看信息的printf。在调试工具中,我觉得printf可能是使用最顺手的一个工具。这让我感觉到软件是活的,计算机是活的,它们是可以与我们进行交流的。

邯郸学步,我也获得了这个存储查看的信息。

进行信息打印,得出来的信息其实也很容易验证软件的功能是否符合我的期待。工作这么久,我做软件调试的时候可能还是过重依赖于高端的调试器。现在体验一下这种软件的仿真功能,感觉设计还真是不错!

我增加了一点链表操作的测试,主要是看了一下节点的删除功能。同时,也看一下链表的尾节点信息。具体的测试代码如下:

int main(void)
{
    struct xLIST_ITEM *p_item;
    UBaseType_t list_item_number;    printf("start simulation...\n");    vListInitialise(&List_Test);    vListInitialiseItem(&List_Item1);
    vListInitialiseItem(&List_Item2);
    vListInitialiseItem(&List_Item3);    List_Item1.xItemValue = 1;
    List_Item2.xItemValue = 2;
    List_Item3.xItemValue = 3;    vListInsert(&List_Test, &List_Item2);
    vListInsert(&List_Test, &List_Item3);
    vListInsert(&List_Test, &List_Item1);    printf("address of List_Test: 0x%p\n", &List_Test);
    printf("address of List_Item1: 0x%p\n", &List_Item1);
    printf("address of List_Item2: 0x%p\n", &List_Item2);
    printf("address of List_Item3: 0x%p\n", &List_Item3);
    printf("number of items: %d\n", List_Test.uxNumberOfItems);
    p_item = List_Test.pxIndex->pxNext;
    printf("item 1: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 2: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 3: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item end: 0x%p\n", p_item);    printf("\ntry to remove List_Item2...\n");
    list_item_number = uxListRemove(&List_Item2);
    printf("item number of List_Test: %d\n", list_item_number);    printf("address of List_Test: 0x%p\n", &List_Test);
    printf("address of List_Item1: 0x%p\n", &List_Item1);
    printf("address of List_Item2: 0x%p\n", &List_Item2);
    printf("address of List_Item3: 0x%p\n", &List_Item3);
    printf("number of items: %d\n", List_Test.uxNumberOfItems);
    p_item = List_Test.pxIndex->pxNext;
    printf("item 1: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 2: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 3: 0x%p\n", p_item);    for(;;)
    {
        /* no code */
    }    return 0;
}

运行仿真,对应的结果如下:

删除之后,继续往后接着就碰到了尾结点。这个跟预期的效果也是一样的。

进一步进行测试的扩展,看一下双向链表是否是一个环形逻辑结构。修改代码如下:

int main(void)
{
    struct xLIST_ITEM *p_item;
    UBaseType_t list_item_number;    printf("start simulation...\n");    vListInitialise(&List_Test);    vListInitialiseItem(&List_Item1);
    vListInitialiseItem(&List_Item2);
    vListInitialiseItem(&List_Item3);    List_Item1.xItemValue = 1;
    List_Item2.xItemValue = 2;
    List_Item3.xItemValue = 3;    vListInsert(&List_Test, &List_Item2);
    vListInsert(&List_Test, &List_Item3);
    vListInsert(&List_Test, &List_Item1);    printf("address of List_Test: 0x%p\n", &List_Test);
    printf("address of List_Item1: 0x%p\n", &List_Item1);
    printf("address of List_Item2: 0x%p\n", &List_Item2);
    printf("address of List_Item3: 0x%p\n", &List_Item3);
    printf("number of items: %d\n", List_Test.uxNumberOfItems);
    p_item = List_Test.pxIndex->pxNext;
    printf("item 1: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 2: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 3: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item end: 0x%p\n", p_item);    printf("\ntry to remove List_Item2...\n");
    list_item_number = uxListRemove(&List_Item2);
    printf("item number of List_Test: %d\n", list_item_number);    printf("address of List_Test: 0x%p\n", &List_Test);
    printf("address of List_Item1: 0x%p\n", &List_Item1);
    printf("address of List_Item2: 0x%p\n", &List_Item2);
    printf("address of List_Item3: 0x%p\n", &List_Item3);
    printf("number of items: %d\n", List_Test.uxNumberOfItems);
    p_item = List_Test.pxIndex->pxNext;
    printf("item 1: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 2: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 3: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 4: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 5: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 6: 0x%p\n", p_item);
    p_item = p_item->pxNext;
    printf("item 7: 0x%p\n", p_item);    for(;;)
    {
        /* no code */
    }    return 0;
}

仿真运行效果:

这个结果也是很符合预期的。

看完这部分,其实本身链表相关的技能或者知识没有什么变化。但是从仿真工具的使用上的确是收获不少。工具用着比较顺手,关于前面的代码分析不妨再进行一部分测试。

第一部分是关于节点插入函数的,我修改成了如下的逻辑:

/* 将节点按照升序排列插入到链表 */
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
	ListItem_t *pxIterator;	/* 获取节点的排序辅助值 */
	const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;	/* 寻找节点要插入的位置 */
	if( xValueOfInsertion == portMAX_DELAY )
	{
		pxIterator = pxList->xListEnd.pxPrevious;
        vListInsertEnd(pxList, pxNewListItem);
        return;
	}
	else
	{
		for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd );
		     pxIterator->pxNext->xItemValue <= xValueOfInsertion; 
			 pxIterator = pxIterator->pxNext )
		{
			/* 没有事情可做,不断迭代只为了找到节点要插入的位置 */			
		}
	}	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxNext->pxPrevious = pxNewListItem;
	pxNewListItem->pxPrevious = pxIterator;
	pxIterator->pxNext = pxNewListItem;	/* 记住该节点所在的链表 */
	pxNewListItem->pvContainer = ( void * ) pxList;	/* 链表节点计数器++ */
	( pxList->uxNumberOfItems )++;
}

为了激活这一段代码运行,我把原来的测试代码中的一行代码做了修改:

如果分析没有错误,修改后的软件应该可以运行出来与之前一样的效果。运行效果如下:

从运行结果看,分析是准确的。

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

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

相关文章

2 月 7 日算法练习- 数据结构-树状数组

树状数组 lowbit 在学习树状数组之前&#xff0c;我们需要了解lowbit操作&#xff0c;这是一种位运算操作&#xff0c;用于计算出数字的二进制表达中的最低位的1以及后面所有的0。 写法很简单&#xff1a; int lowbit&#xff08;int x&#xff09;&#xff5b;return x &am…

2024.02.08

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget) {ui->setupUi(this);this->setWindowIcon(QIcon(":/zh.png"));ui->lineEdit->setPlaceholderText("账号/手…

WordPress Plugin HTML5 Video Player SQL注入漏洞复现(CVE-2024-1061)

0x01 产品简介 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 0x02 漏洞概述 WordPress Plugin HTML5 Video Player 插件 get_v…

Python进阶--爬取美女图片壁纸(基于回车桌面网的爬虫程序)

目录 一、前言 二、爬取下载美女图片 1、抓包分析 a、分析页面 b、明确需求 c、抓包搜寻 d、总结特点 2、编写爬虫代码 a、获取图片页网页源代码 b、提取所有图片的链接和标题 c、下载并保存这组图片 d、 爬取目录页的各种类型美女图片的链接 e、实现翻页 三、各…

ZooKeeper安装及配置(Windows版)

步骤&#xff1a; 1.官网下载二进制版本ZooKeeper安装包。 2.解压到你要安装的目录下 3.配置 3.1进入目录 D:\Install\apache-zookeeper-3.9.1-bin 新增两个文件夹&#xff1a;data和log 3.2 进入目录D:\Install\apache-zookeeper-3.9.1-bin\conf 复制zoo_sample.cfg文件&a…

手把手教你开发Python桌面应用-PyQt6图书管理系统-主窗体点击菜单显示功能窗体实现

锋哥原创的PyQt6图书管理系统视频教程&#xff1a; PyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~_哔哩哔哩_bilibiliPyQt6图书管理系统视频教程 Python桌面开发 Python入门级项目实战 (无废话版) 火爆连载更新中~共计24条视频&…

【人工智能】人工智能 – 引领未来科技的潮流

写在前面 引言红利挑战结论 引言 人工智能是指使计算机系统表现出类似于人类智能的能力。其目标是实现机器具备感知、理解、学习、推理和决策等智能行为。人工智能的发展可以追溯到上世纪50年代&#xff0c;随着计算机技术和算法的不断进步&#xff0c;人工智能得以实现。 今天…

visual studio code could not establish connection to *: XHR failed

vscode远程连接服务器时&#xff0c;输入密码&#xff0c;又重新提示输入密码&#xff0c;就这样循环了好几次&#xff0c;然后会报上述的错误。由于我是window系统&#xff0c;我用cmd&#xff0c;然后ssh */你的IP地址/*发现可以远程到服务器上&#xff0c;但是通过Vscode就不…

向量搜索查询faiss、annoy

首先介绍annoy : 转发空间&#xff1a;https://download.csdn.net/blog/column/10872374/114665212 Annoy是高维空间求近似最近邻的一个开源库。 Annoy构建一棵二叉树&#xff0c;查询时间为O(logn)。 Annoy通过随机挑选两个点&#xff0c;并使用垂直于这个点的等距离超平面…

新书速览|PyTorch 2.0深度学习从零开始学

实战中文情感分类、拼音汉字转化、中文文本分类、拼音汉字翻译、强化学习、语音唤醒、人脸识别 01 本书简介 本书以通俗易懂的方式介绍PyTorch深度学习基础理论&#xff0c;并以项目实战的形式详细介绍PyTorch框架的使用。为读者揭示PyTorch 2.0进行深度学习项目实战的核心技…

Git介绍和常用命令说明

目录 一、Git概述 1.1 Git是什么 1.2 Git有什么用 1.3 Git仓库介绍 二、Git下载与安装 三、Git代码托管服务&#xff08;远程仓库&#xff09; 四、Git常用命令 4.1 设置用户信息 4.2 获取Git仓库 4.2.1 本地初始化Git仓库 4.2.2 从远程仓库克隆 4.3 本地仓库操作 …

相机图像质量研究(10)常见问题总结:光学结构对成像的影响--光圈

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

SERVLET线程模型

1. SERVLET线程模型 Servlet规范定义了两种线程模型来阐明Web容器应该如何在多线程环境中处理servlet。第一种模型称为多线程模型,默认在此模型内执行所有servlet。在此模型中,每次客户机向servlet发送请求时Web容器都启动一个新线程。这意味着可能有多个线程同时访问servle…

机器人运动学林沛群——旋转矩阵

旋转矩阵 基本概念 三个主轴&#xff0c;可以看作是三个向量&#xff0c;为b在a的表达&#xff0c;以a为基准 旋转矩阵 B相对于A的姿态&#xff1a; B A R [ A X B ^ A Y B ^ A Z B ^ ] [ X ^ B ⋅ X ^ A Y ^ B ⋅ X ^ A Z ^ B ⋅ X ^ A X ^ B ⋅ Y ^ A Y ^ B ⋅ Y ^ A Z …

牛客网SQL264:查询每个日期新用户的次日留存率

官网链接&#xff1a; 牛客每个人最近的登录日期(五)_牛客题霸_牛客网牛客每天有很多人登录&#xff0c;请你统计一下牛客每个日期新用户的次日留存率。 有一个登录(login。题目来自【牛客题霸】https://www.nowcoder.com/practice/ea0c56cd700344b590182aad03cc61b8?tpId82 …

C语言笔试题之实现C库函数 strstr()(设置标志位)

实例要求&#xff1a; 1、请你实现C库函数strstr()&#xff08;stdio.h & string.h&#xff09;&#xff0c;请在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;&#xff1b;2、函数声明&#xff1a;int strStr(char* h…

5G NR 信道号计算

一、5G NR的频段 增加带宽是增加容量和传输速率最直接的方法&#xff0c;目前5G最大带宽将会达到400MHz&#xff0c;考虑到目前频率占用情况&#xff0c;5G将不得不使用高频进行通信。 3GPP协议定义了从Sub6G(FR1)到毫米波(FR2)的5G目标频谱。 其中FR1是5G的核心频段&#xff0…

米贸搜|Facebook在购物季使用的Meta广告投放流程

一、账户简化 当广告系列开始投放后&#xff0c;每个广告组都会经历一个初始的“机器学习阶段”。简化账户架构可以帮助AI系统更快获得广告主所需的成效。例如&#xff1a; 每周转化次数超过50次的广告组&#xff0c;其单次购物费用要低28%&#xff1b;成功结束机器学习阶段的…

MySQL索引怎么提高查询的速度?

目录 一、MySQL介绍 二、什么是索引 三、为什么要用索引 四、索引如何提高查询速度 一、MySQL介绍 MySQL是一个开源的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;它是目前最流行和广泛使用的数据库之一。MySQL由瑞典MySQL AB公司开发&#xff0c;并在…

NXP恩智浦电源管理芯片 PIMC VR5510 (配套S32G)芯片手册(I2C通信)-翻译版

文章目录 1. 基本概述2. 简化应用视图3. 特点4. 应用5. 订购信息6. 芯片内部区块视图7. Pin脚信息7.1 Pin 描述7.2 Pinning 8. 产品特性概述8.1 最大额定值8.2 电气特性8.3 操作范围8.4 热力范围8.5 EMC合规性8.6 功能状态图8.7 功能设备操作8.8 主要状态机8.9 深度故障安全状态…