FreeRTOS链表

本文介绍了链表的基本概念,强调了其动态存储分配和灵活的数据结构特性。然后,文章转向FreeRTOS中的链表操作,描述了如何在FreeRTOS环境中设置链表,包括在list.c和list.h文件中定义结构体,并预告了后续章节将讨论链表的删除和插入功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#1.链表的定义
链表是一种常见的基础数据结构,结构体指针在这里得到了充分的利用。链表可以动态的进行存储分配,也就是说,链表是一个功能极为强大的数组,他可以在节点中定义多种数据类型,还可以根据需要随意增添,删除,插入节点。链表都有一个头指针,一般以head来表示,存放的是一个地址。链表中的节点分为两类,头结点和一般节点,头结点是没有数据域的。链表中每个节点都分为两部分,一个数据域,一个是指针域。说到这里你应该就明白了,链表就如同车链子一样,head指向第一个元素:第一个元素又指向第二个元素;……,直到最后一个元素,该元素不再指向其它元素,它称为“表尾”,它的地址部分放一个“NULL”(表示“空地址”),链表到此结束。

作为有强大功能的链表,对他的操作当然有许多,比如:链表的创建,修改,删除,插入,输出,排序,反序,清空链表的元素,求链表的长度等等。

初学链表,一般从单向链表开始

--->NULL
head

这是一个空链表。

 ---->[p1]---->[p2]...---->[pn]---->[NULL]
head   p1->next  p2->next   pn->next

有n个节点的链表。

创建链表

typedef struct student{
	int score;
	struct student *next;
} LinkList;

一般创建链表我们都用typedef struct,因为这样定义结构体变量时,我们就可以直接可以用LinkList *a;定义结构体类型变量了。

初始化一个链表,n为链表节点个数。

LinkList *creat(int n){
	LinkList *head, *node, *end;//定义头节点,普通节点,尾部节点;
	head = (LinkList*)malloc(sizeof(LinkList));//分配地址
	end = head;         //若是空链表则头尾节点一样
	for (int i = 0; i < n; i++) {
		node = (LinkList*)malloc(sizeof(LinkList));
		scanf("%d", &node->score);
		end->next = node;
		end = node;
	}
	end->next = NULL;//结束创建
	return head;

#2.FreeRTOS链表操作
首先把我原来发过的FreeRTOS工程建立模板拷贝一份,改名为FreeRTOS-list,将FreeRTOS源码移植进FreeRTOS-list\FreeRTOS\include 路径下。
在这里插入图片描述
其次依次添加到工程中,并添加路径。同时创建两个文件分别是list.c保存在FreeRTOS-list\USER\portable路径下和list.h保存在FreeRTOS-list\USER\include路径下。(添加路径)
在这里插入图片描述
在这里前期工作我们已经准备好,接下来就要在list.c和list.h中编写程序代码了。首先我们要建立一个链表,我们要在list.h中定义一个结构体。这里一定要引用#include “FreeRTOS.h”,不然会报错。


/* 节点结构体定义 */
struct xLIST_ITEM
{
	TickType_t xItemValue;//辅助值,用来帮助节点做顺序排列	
	struct xLIST_ITEM *  pxNext;//指向链表下一个节点		
	struct xLIST_ITEM *  pxPrevious;//指向链表前一个节点
	void * pvOwner;	//指向拥有该节点的内核对象,通常是TCB
	void *  pvContainer;//指向该节点所在链表
};
typedef struct xLIST_ITEM ListItem_t;  //节点数据类型重定义
接下来我们将对链表进行增删改查,这里我将不在说明具体请看代码。list.h文件中:
#ifndef LIST_H
#define LIST_H
/*
************************************************************************
*                    头文件
************************************************************************
*/
#include "FreeRTOS.h"
/*
************************************************************************
*                              结构体定义
************************************************************************
*/
/* 节点结构体定义 */
struct xLIST_ITEM
{
	TickType_t xItemValue;//辅助值,用来帮助节点做顺序排列	
	struct xLIST_ITEM *  pxNext;//指向链表下一个节点		
	struct xLIST_ITEM *  pxPrevious;//指向链表前一个节点
	void * pvOwner;	//指向拥有该节点的内核对象,通常是TCB
	void *  pvContainer;//指向该节点所在链表
};
typedef struct xLIST_ITEM ListItem_t;  //节点数据类型重定义



/* mini节点结构体定义,作为双向链表的结尾,因为双向链表是首尾相连的,头和尾一样 */
struct xMINI_LIST_ITEM
{
	TickType_t xItemValue;//辅助值,用来帮助节点做顺序排列	
	struct xLIST_ITEM *  pxNext;//指向链表下一个节点	
	struct xLIST_ITEM *  pxPrevious;//指向链表前一个节点
};
typedef struct xMINI_LIST_ITEM MiniListItem_t; //最小节点数据类型重定义


/* 链表结构体定义*/
typedef struct xLIST
{
	UBaseType_t uxNumberOfItems;    /*链表节点计数器*/
	ListItem_t *  pxIndex;			/*链表节点索引指针 */
	MiniListItem_t xListEnd;		/* 链表最后一个节点 */
} List_t;


/*
************************************************************************
*                                ºê¶¨Òå
************************************************************************
*/
/* 初始化节点拥有者 */
#define listSET_LIST_ITEM_OWNER( pxListItem, pxOwner )		( ( pxListItem )->pvOwner = ( void * ) ( pxOwner ) )
/* 获取节点拥有者 */
#define listGET_LIST_ITEM_OWNER( pxListItem )	( ( pxListItem )->pvOwner )

/* 初始化节点排序辅助值*/
#define listSET_LIST_ITEM_VALUE( pxListItem, xValue )	( ( pxListItem )->xItemValue = ( xValue ) )

/* 获取节点排序辅助值 */
#define listGET_LIST_ITEM_VALUE( pxListItem )	( ( pxListItem )->xItemValue )

/*获取链表根节点的节点计数器值*/
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext->xItemValue )

/* 获取链表的入口节点*/
#define listGET_HEAD_ENTRY( pxList )	( ( ( pxList )->xListEnd ).pxNext )

/* 获取链表的第一个节点 */
#define listGET_NEXT( pxListItem )	( ( pxListItem )->pxNext )

/* 获取链表最后一个节点 */
#define listGET_END_MARKER( pxList )	( ( ListItem_t const * ) ( &( ( pxList )->xListEnd ) ) )

/*判断链表是否为空*/
#define listLIST_IS_EMPTY( pxList )	( ( BaseType_t ) ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) )

/*获取链表的节点数*/
#define listCURRENT_LIST_LENGTH( pxList )	( ( pxList )->uxNumberOfItems )

/* 获取链表的owner即TCB */
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )										\
{																							\
	List_t * const pxConstList = ( pxList );											    \
	/* 节点索引指向链表第一个节点调整节点索引指针,指向一个节点,如果当前链表有N个节点,当地N次调用该函数时,pxIndex指向第N个节点*/\
	( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;							\
	/* 链表为空 */                                                                       \
	if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )	\
	{																						\
		( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;						\
	}																						\
	/*获取链表的owner即TCB  */                                                             \
	( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;											 \
}

#define listGET_OWNER_OF_HEAD_ENTRY( pxList )  ( (&( ( pxList )->xListEnd ))->pxNext->pvOwner )

/*
************************************************************************
*                                º¯ÊýÉùÃ÷
************************************************************************
*/
void vListInitialise( List_t * const pxList );
void vListInitialiseItem( ListItem_t * const pxItem );
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem );
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem );
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove );
#endif /* LIST_H */

list.c文件中:

#include "FreeRTOS.h"
#include <stdlib.h>
#include "list.h"


/*链表根节点初始化 */
void vListInitialise( List_t * const pxList )
{
	/*将链表索引指针指向最后一个节点*/
	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );

	/* 将链表最后一个节点的辅助排序得知设置为最大,确保该节点就是链表最后一个节点*/
	pxList->xListEnd.xItemValue = portMAX_DELAY;

    /* 将最后一个节点的pxNext和pxPrevious 指针指向自身,为空  */
	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );

	/* 初始化链表节点计数器的值为0,链表为空 */
	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
}

/*节点初始化 */
void vListInitialiseItem( ListItem_t * const pxItem )
{
	/* 初始化该节点所在链表为空,表示节点还没有插入任何值*/
	pxItem->pvContainer = NULL;
}


/*将节点插入到链表尾部 */
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
	ListItem_t * const pxIndex = pxList->pxIndex;

	pxNewListItem->pxNext = pxIndex;
	pxNewListItem->pxPrevious = pxIndex->pxPrevious;
	pxIndex->pxPrevious->pxNext = pxNewListItem;
	pxIndex->pxPrevious = pxNewListItem;

	/* 记住该节点所在的索引*/
	pxNewListItem->pvContainer = ( void * ) pxList;

	/* 链表节点计数器++ */
	( pxList->uxNumberOfItems )++;
}


/* 将节点按升序排列插入到链表 */
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;
	}
	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 )++;
}


/*将节点从链表删除 */
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
	/*获取节点所在链表 */
	List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;

	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

	/* Make sure the index is left pointing to a valid item. */
	if( pxList->pxIndex == pxItemToRemove )
	{
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}

	/*初始化该节点所在链表为空,表示没有插入任何元素 */
	pxItemToRemove->pvContainer = NULL;
	
	/*链表计数器-- */
	( pxList->uxNumberOfItems )--;

	/*返回链表中剩余节点个数 */
	return pxList->uxNumberOfItems;
}


下一章我将对链表删除和插入进行详细解说,以上程序对操作系统链表实现所有功能,可以通过软件调试测出结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值