嵌入式c语言单向链表

链表是结合结构体和指针的综合应用,学习之前务必复习结构体和指针的相关知识。

#include<stdio.h>
typedef struct TempHumiListNode_t
{
    uint8_t id;
    uint8_t humi;
    float temp;
    struct TempHumiListNode_t *next;//在ARM32平台中指针类型编译器自动分配4个字节,所以可以在结构体中嵌套一个指向本结构体类型的指针
}TempHumiListNode;
//创建头节点子函数
TempHumiListNode *InitSensorList(void)
{
    TempHumiListNode *header = (TempHumiListNode)malloc(sizeof(TempHumiListNode));
    if(header == NULL)
    {
        return NULL;//申请失败返回NULL
    }
    header->id = 0;
    header->next = NULL;
    return header;//申请成功,返回动态内存首地址
}
//添加节点函数
void AddSensorNode(TempHumiListNode *header, TempHumiListNode *node)
{
	TempHumiListNode *current = header;//初始化为头节点的首地址
	//寻找尾节点,没找到就循环,找到就停止
	while (current->next != NULL)
	{
		current = current->next;
	}
	
	current->next = node;//将尾节点的next指向添加的新节点首地址
	node->next = NULL;//将新节点next指向原来尾节点保存的地址
}
static TempHumiListNode *g_header;//头指针变量
//添加节点,模拟检测温湿度计函数
TempHumiListNode *FindTempHumiSensor(void)
{
	TempHumiListNode *node = (TempHumiListNode *)malloc(sizeof(TempHumiListNode));
	if (node == NULL)
	{
		return NULL;
	}
	
	static uint8_t id = 100;
	node->id = id;
	id--;//每次调用的时候变一下ID,模拟新设备
	node->temp = 20.5f;
	node->humi = 40;
	return node;
}
//遍历节点
void PrintSensorData(TempHumiListNode *header)
{
	TempHumiListNode *current = header->next;
    //如果链表只有1个头节点,指向下一个节点时就是NULL
	if (current == NULL)
	{
		printf("List has no node!\n");//打印链表中没人节点
		return;//直接返回
	}
	//有节点就执行循环,直到指向NULL退出
	while (current != NULL)
	{
		printf("\nSensor id:%d, temp = %.1f, humi = %d.\n",
				current->id, current->temp, current->humi);
		current = current->next;
	}
}
//删除节点
//传入两个参数 头节点,数据域保存的id
void DelSensorNode(TempHumiListNode *header, uint8_t id)
{
	TempHumiListNode *prev = header;//初始化指向头节点
	TempHumiListNode *current = header->next;//初始化指向头节点下一个节点
	
	while (current != NULL)
	{
		if (current->id == id)
		{
			break;//找到对应id的节点直接退出指向后面的语句
		}
		prev = current;
		current = current->next;
	}
    //判断是找到id退出的,还是没找到id退出的,没找到就返回
	if (current == NULL)
	{
		printf("Can not find sensor %d.\n", id);
		return;
	}
	//找到了
	prev->next = current->next;//将删除节点前节点指针域指向删除节点后的地址,就完成了删除节点
	free(current);//释放被删除节点的动态内存
	current = NULL;//将被删除节点的指针指向NULL
}
int main(void)
{
    g_header = InitSensorList();
	if (g_header == NULL)
	{
		return -1;
	}
    TempHumiListNode *node;//局部变量node
    for(unsigned i = 0; i < 3; i--)
    {
        node = FindTempHumiSensor();//调用模拟检测温湿度计函数,保存返回的数据
	    if (node == NULL)
	    {
	    	continue;//申请动态内存失败提前结束本次循环,开始下一次循环
	    }
        AddSensorNode(g_header,node);//申请成功,添加节点函数
    }
    PrintSensorData(g_header);//遍历链表的每个节点并打印数据
    DelSensorNode(g_header,100);//删除掉id为100的节点
    PrintSensorData(g_header);//遍历链表的每个节点并打印数据
    //在添加并打印
	for (uint8_t i = 0; i < 3; i++)
	{
		node = FindTempHumiSensor();
		if (node == NULL)
		{
			continue;
		}
		AddSensorNode(g_header, node);
	}
	PrintSensorData(g_header);
    return 0;
}

链表的创建

typedef struct TempHumiListNode_t
{
    //数据域
    uint8_t id;
    uint8_t humi;
    float temp;
    //指针域
    struct TempHumiListNode_t *next;//在ARM32平台中指针类型编译器自动分配4个字节,所以可以在结构体中嵌套一个指向本结构体类型的指针
}TempHumiListNode;
//创建头节点子函数
TempHumiListNode *InitSensorList(void)
{
    TempHumiListNode *header = (TempHumiListNode)malloc(sizeof(TempHumiListNode));
    if(header == NULL)
    {
        return NULL;//申请失败返回NULL
    }
    return header;//申请成功,返回动态内存首地址
    header->id = 0;
    header->next = NULL;
}

注意:如果结构体里嵌套的是结构体类型的普通变量,由于这个结构体还没有执行完毕,

编译器不知道给分配多少内存,所以会报错。

链表添加节点

尾节点的next成员保存地址为NULL;

先找到尾节点,定义一个局部变量TempHumiListNode *current,从头节点开始循环遍历节点:

TempHumiListNode *current = header;
//目标是找到边界,next保存的是NULL的那个节点,如果找到了就为假,停止循环
while(current->next != NULL)
{
    current = current->next;//使current从一个节点指向下一个节点
}

找到尾节点后添加新节点到链表尾部

//添加节点函数方案1
void AddSensorNode(TempHumiListNode *header, TempHumiListNode *node)
{
	TempHumiListNode *current = header;//初始化为头节点的首地址
	//寻找尾节点,没找到就循环,找到就停止
	while (current->next != NULL)
	{
		current = current->next;//从当前节点指向下一个节点
	}
	
	current->next = node;//将尾节点的next指向添加的新节点首地址
	node->next = NULL;//将新节点next指向原来尾节点保存的地址
}

注意:这种方法是判断current保存的下一个地址是不是NULL,current本身指向的是尾节点,在current后面就是新的节点。

添加节点的第二种方案

使用两个指针变量遍历链表。

void AddSensorNode(TempHumiListNode *header, TempHumiListNode *node)
{
    TempHumiListNode *prev = header;//初始值header
    TempHumiListNode *current = header->next;//初始值header下一个节点
    //寻找尾节点,没找到就循环,找到就停止,prev 指向尾节点,current指向NULL
    while(current != NULL)
    {
        prev = current;//prev 指向下一个节点
        current = current->next;//从当前节点指向下一个节点
    }
    //找到后将新节点添加到链表尾部
    prev->next = node;//prev的next成员保存新节点的首地址
    node->next = NULL;//将新节点的next成员赋值为NULL
}

注意:这种方法是判断prev指向的是不是尾节点,current保存的地址是不是尾节点的下一项NULL,current本身指向的就是尾节点的next,当current指向NULL时循环已经退出了,此时prev保存的就是为尾节点,prev的next指向的就是新的节点。

总结:方案1更简洁一些,方案2其实是为了和后面章节删除节点统一风格,方案2比较常用建以掌握。

遍历链表节点

  1. 考虑指针怎么指向下一个地址;
  2. 考虑循环的边界值,什么时候退出循环。
//遍历节点
void PrintSensorData(TempHumiListNode *header)
{
	TempHumiListNode *current = header->next;
    //如果链表只有1个头节点,指向下一个节点时就是NULL
	if (current == NULL)
	{
		printf("List has no node!\n");//打印链表中没人节点
		return;//直接返回
	}
	//有节点就执行循环,直到指向NULL退出
	while (current != NULL)
	{
		printf("\nSensor id:%d, temp = %.1f, humi = %d.\n",
				current->id, current->temp, current->humi);
		current = current->next;
	}
}

删除节点

  1. 删除的第一步还是先找到这个节点,也就是遍历;
  2. 找到以后退出循环,推出循环的边界值;
  3. 删除节点后把删除节点前一项的指针域指向删除节点的后一项。

之前在添加节点方案2时说过,遍历方式与删除节点一样,所以这里应该很容易理解

//删除节点
//传入两个参数 头节点,数据域保存的id
void DelSensorNode(TempHumiListNode *header, uint8_t id)
{
	TempHumiListNode *prev = header;//初始化指向头节点
	TempHumiListNode *current = header->next;//初始化指向头节点下一个节点
	
	while (current != NULL)
	{
		if (current->id == id)
		{
			break;//找到对应id的节点直接退出
		}
		prev = current;
		current = current->next;
	}
    //没找到就返回
	if (current == NULL)
	{
		printf("Can not find sensor %d.\n", id);
		return;
	}
	//找到了
	prev->next = current->next;//将删除节点前节点指针域指向删除节点后的地址,就完成了删除节点
	free(current);//释放被删除节点的动态内存
	current = NULL;//将被删除节点的指针指向NULL
}

完整的代码已经放在前面了,请大家详细阅读注释,注释已经写的很清楚了,如果还是看不懂的话建议观看前面的章节,结构体与指针增强一下记忆,c语言基础部分后面会陆续更新。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jarrett_Zheng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值