在嵌入式软件开发中,涉及到双机通信过程中,接收方有多条数据接收,并要逐条处理的情况,这样就需要先接收,存储到缓存中,然后再从缓存中读取并逐一处理。针对这种场景,通常有两种方式,一是建立一个多维数组,每一纬用于存储一条数据,这种方式比较直观,操作方便,涉及到多维数组的遍历,数组的数据写入和读取等常规操作,缺点是因为是多维数组,在定义时就要确定数组的维数和数组的长度,比如data_list[4][512];数组的维数和长度都要按照实际情况的最大值来设定,这样有可能带来空间上的浪费,为了确保某一条不常用的长数据的存储就要将所有的数据长度都定义长最大长度,比如某种情况下发送方有可能发送来超过1024字节的数据,那么上面的数据就得定义成data_list[4][2048];造成空间的极大浪费,对于资源敏感的嵌入式开发来说不能忍受,而且数据的条数固定在4条以内,超过4条就会造成接收数据不完整,不够灵活。所以我们这里介绍通过单项链表的方式来逐条接收连接数据,每条数据的大小都按实际大小动态分配内存,然后接入到链表中,处理的时候逐一遍历链表来访问每条数据。优点是比较灵活,节约内存空间,缺点是需要动态分配内存,接入链表,然后使用完成后释放动态内存,操作要精准,避免内存泄漏。
重点记录如下:
1.定义链表数据节点结构
typedef struct data_note
{
struct data_note *p_next;
char *data;
uint16_t len;
} data_note;
typedef struct
{
uint32_t parts;
char name[AT_CMD_NAME_LEN];
uint32_t parameter_num;
data_note *p_para_line;
}dbg_cmd_t;
for(i=0;i<nDatas;i++)
{
int len=para_info[i].len;
data_note *p_para_line=rt_malloc(sizeof(data_note));
if(p_para_line==RT_NULL)
{
LOGPV("#Err:p_para_line malloc fail\r\n");
}
p_para_line->data=rt_malloc(len+1);
if(p_para_line==RT_NULL)
{
LOGPV("#Err:data malloc fail\r\n");
}
p_para_line->len =len;
memcpy(p_para_line->data,para_info[i].pstr,len);
p_para_line->data[len]='\0';
//2.新创节点插入到头节点
p_para_line->p_next=dbgCmd.p_para_line;
dbgCmd.p_para_line =p_para_line;
}
3.因为插入节点时都是后接入作为链表头,所以链表是和接收数据的顺序是反序的,后接入的在前,先接入的在后,所以接收完成需要反转一下:
static void reverse_at_para_line(dbg_cmd_t *p_atcmd)
{
data_note *pcur,*pnext;
pcur = p_atcmd->p_para_line;
p_atcmd->p_para_line = NULL;
while (pcur != NULL)
{
pnext = pcur->p_next;
pcur->p_next = p_atcmd->p_para_line;//当前节点指向上一个头节点
p_atcmd->p_para_line = pcur; //更新当前节点作为头节点,一直移动到最后,即原来链表最后的节点翻转为新链表的头节点,p_line最终存储的是头节点
pcur = pnext;
}
}
4.最后在处理完链表后记得释放动态申请的链表节点和里面的数据指针:
static void free_para_line(dbg_cmd_t *p_atcmd)
{
data_note *pcur,*pnext;
pcur = p_atcmd->p_para_line;
p_atcmd->p_para_line = NULL;
while (pcur != NULL)
{
pnext = pcur->p_next;
rt_free(pcur->data);
pcur->data=RT_NULL;
rt_free(pcur);
pcur =RT_NULL;
pcur = pnext;
}
}