单向链表

使用场景

链表在内存空间中的存储是随机的,通过指针单(双向)连接,相较于内存空间连续的数组,优点在于链表长度不固定(可以add或del),缺点在于不能够像数组一样通过下标的方式查找到节点,而是需要遍历链表。

  • 裸机程序中用于在C语言中管理相同的对象,比如停车场车辆管理程序中,通过链表节点的增删改查记录车辆的信息。 车辆管理程序案例 车辆管理程序案例

  • RTOS中的链表是关键部分,无论是线程执行链表,还是将所有的进程间通信(ipc)以及其他对象(object)链接在一起进行管理。

代码示例

语言:C
编译器:Keil5

/*停车场管理系统的链表使用案例*/
//全局变量 global value
struct node{
	struct node *pNext;
	char car_type[5];
	char car_name[5];
	int year;
	int month;
	int day;
	int hour;
	int min;
	int sec;
	unsigned long total_sec;
};
struct head{
	struct node *pNext;
	int C_Count;
	int V_Count;
	int I_Count;
};

/*
* 功能:在链表中插入节点
* 参数:phead-链表头节点,pnode-等待插入的节点
*/
void LIST_ADD_NODE(struct head *phead, struct node *pnode)
{
	struct node *list = phead->pNext;
	if(list)
	{
		while(list->pNext)
		{
			list = list->pNext;
		}
		list->pNext = pnode;
	}
	else
	{
		phead->pNext = pnode;
	}
	//可以忽略,对头节点结构体的变量进行处理
	if(pnode->car_type[0] == 'C')
	{
		phead->C_Count ++;
		phead->I_Count --;
	}
	else if(pnode->car_type[0] == 'V')
	{
		phead->V_Count ++;
		phead->I_Count --;	
	}
}

/*
* 功能:在链表中删除节点
* 参数:phead-链表头节点,number-需要被删除节点结构体中的一* 个变量值,可以是一个唯一的值,比如序号。
*/
void LIST_DEL_NODE(struct head *phead, char *number)
{
	struct node *list = phead->pNext;
	struct node *pnode;
	//如果头节点没有下一个node
	if(!list) return;
	if(strcmp(list->car_name, number))
	{
		//只要链表的当前节点还有下一个节点,并且下一节点的车牌号与目标车牌号不相同
		while((list->pNext) && strcmp(list->pNext->car_name, number))
		{
			list = list->pNext;
		}
		if(list->pNext != NULL)
		{
			pnode = list->pNext;
			list->pNext = list->pNext->pNext;
		}
		else
		{
			//您在试图删除一个不存在的节点
			return;
		}
	}
	else
	{
		pnode = phead->pNext;
		phead->pNext = phead->pNext->pNext;
	}
	if(pnode->car_type[0] == 'C')
	{
		phead->C_Count --;
		phead->I_Count ++;
	}
	else if(pnode->car_type[0] == 'V')
	{
		phead->V_Count --;
		phead->I_Count ++;	
	}
}

/*
* 功能:遍历结构体,根据名称字符串对应节点结构体找到节点
* 参数:phead-链表头节点,name-链表中某一节点的名称
*/
struct node* LIST_FIND_NODE_BY_NAME(struct head *phead, char *name)
{
	struct node* p = phead->pNext;
	while(p)
	{
		if(strcmp(p->car_name,name) == 0)
			return p;
		else
			p = p->pNext;
	}
	return NULL;
}

void main()
{
	...

	//创建链表
	car_list = (struct head *)malloc(sizeof(struct head));
	car_list->I_Count = IDLE_Count;
	car_list->C_Count = CNBR_Count;
	car_list->V_Count = VNBR_Count;

	...
}

注意事项

如果将新malloc的指针变量存储到链表中后不要free掉这个这个指针变量,因为这个指针变量代表的是一块内存空间的起始地址,这块内存空间中是有数据的。否则下一次malloc很有可能会再次malloc到这个地方,但是此处是有数据的,就会导致覆盖。