這篇文章主要為大家展示了“鏈表在STM32中怎么用”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學習一下“鏈表在STM32中怎么用”這篇文章吧。
10多年的上海網(wǎng)站建設經(jīng)驗,針對設計、前端、開發(fā)、售后、文案、推廣等六對一服務,響應快,48小時及時工作處理。營銷型網(wǎng)站的優(yōu)勢是能夠根據(jù)用戶設備顯示端的尺寸不同,自動調(diào)整上海建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)建站從事“上海網(wǎng)站設計”,“上海網(wǎng)站推廣”以來,每個客戶項目都認真落實執(zhí)行。
在程序中經(jīng)常面臨一個問題,我們需要保存一定數(shù)量的對象,但是對象數(shù)目是不確定的,或者說是隨時增加或減少的。這時候最簡單的方法是創(chuàng)建一個足夠大的數(shù)組,用來存儲這些對象。我最近開發(fā)一個項目就遇到類似的問題,下面我把問題簡化一下。
需求:通過PC下發(fā)一些矩形的坐標和寬高信息,每個區(qū)域有個ID編號,并在這些矩形內(nèi)填充一定的數(shù)據(jù)。
通常情況下,最簡單易懂的做法是,限制最多5個區(qū)域,每個區(qū)域存儲1K數(shù)據(jù)。因此設置了這樣的一個結(jié)構(gòu)體(類似于面向?qū)ο笳Z言里說的成員屬性)。
typedef struct Area_Inf { uint8_t ID; uint8_t X; uint8_t Y; uint8_t Width; uint8_t Height; uint8_t data_len; }Area_Inf_Typedef;
然后定義結(jié)構(gòu)體的實體。
#define Area_Num 5 #define Area_cache 1024 Area_Inf_Typedef Area_Info[Area_Num]; uint8_t Area_Data[Area_Num*Area_cache];//存儲區(qū)域的數(shù)據(jù) /*找到ID為5的區(qū)域,并將數(shù)據(jù)拷貝出去*/ void main() { uint8_t i; uint8_t data[1024]; for(i = 0;i < Area_Num;i++) { if(Area_Info[i].ID == 5) { memcpy(data,&Area_Data[i*Area_cache ],Area_Info[i].data_len); } } }
上面這種做法是最簡單易懂的,但不靈活,比如有客戶要求10個區(qū)域,但是每個區(qū)域存儲的數(shù)據(jù)很少,根本用不到1K。雖然上面的程序已經(jīng)使用了宏定義,只需要修改宏定義就能實現(xiàn)要求。但這意味著不同的客戶,需要編譯不同的固件。
#define Area_Num 10 #define Area_cache 512
這樣的程序存在的問題:
1、在內(nèi)存資源很緊缺的單片機程序中,當區(qū)域數(shù)據(jù)很少時,這種程序的處理方法浪費了大量的內(nèi)存空間。
2、數(shù)值固定,需要存儲更多區(qū)域,即使還有內(nèi)存,還是需要修改宏定義,重新編譯固件,不靈活。
這時需要引入鏈表來解決這個問題。
鏈表實際上是線性表的鏈式存儲結(jié)構(gòu),與數(shù)組不同的是,它是用一組任意的存儲單元來存儲線性表中的數(shù)據(jù),存儲單元不一定是連續(xù)的,且鏈表的長度不是固定的,鏈表數(shù)據(jù)的這一特點使其可以非常的方便地實現(xiàn)節(jié)點的插入和刪除操作。鏈表的每個元素稱為一個節(jié)點,每個節(jié)點都可以存儲在內(nèi)存中的不同的位置,為了表示每個元素與后繼元素的邏輯關(guān)系,以便構(gòu)成“一個節(jié)點鏈著一個節(jié)點”的鏈式存儲結(jié)構(gòu),除了存儲元素本身的信息外,還要存儲其直接后繼信息,因此,每個節(jié)點都包含兩個部分,第一部分稱為鏈表的數(shù)據(jù)區(qū)域,用于存儲元素本身的數(shù)據(jù)信息。
對于上面的問題,我們使用鏈表解決,需要配合內(nèi)存管理才能實現(xiàn)。內(nèi)存管理這一塊,大家可以自己編寫內(nèi)存管理驅(qū)動,也可以使用C庫的malloc和free函數(shù)。如何字節(jié)編寫內(nèi)存管理驅(qū)動不是本文的重點,下文將使用C庫的malloc和free函數(shù)進行內(nèi)存管理。
使用鏈表的方式,在原有的成員屬性結(jié)構(gòu)體的前提上,還要再封裝多一層鏈表管理。以單向鏈表為例:
typedef struct Area_Inf { uint8_t ID; uint8_t X; uint8_t Y; uint8_t Width; uint8_t Height; uint8_t data_len; uint8_t* Area_Data; }Area_Inf_Typedef; typedef struct Area_List_Inf { Area_Inf_Typedef *Area_Inf; struct Area_List_Inf *next_Area_Inf; //用于指向下一個 }Area_List_Inf_Typedef; Area_List_Inf_Typedef *Head_Area_List; //鏈表的頭指針
由于在定義的時候,只定義了一個頭指針,那么它也只是個指向了Area_List_Inf_Typedef也就是鏈表結(jié)構(gòu)體的指針,同樣沒有內(nèi)存空間,在沒有創(chuàng)建新增鏈表之前,它是一個野指針。
所以,在具體應用之前,需要先執(zhí)行一個初始化操作,也就是申請空間給鏈表管理結(jié)構(gòu)體,然后頭指針指向這個空間。
/** * @brief 動態(tài)區(qū)鏈表初始化 * @return int */ int Area_List_Init(void) { //申請鏈表類型大小的空間,并讓頭指針指向它 Head_Area_List = (Area_List_Inf_Typedef*)malloc(sizeof(Area_List_Inf_Typedef)); if(Head_Area_List == NULL) return false; //同時要標記下一個信息為空 Head_Area_List->next_Area_Inf = NULL; return true; }
通過PC下發(fā)一個新的區(qū)域信息后,增加新區(qū)域到鏈表末尾。
/** * @brief 在鏈表末尾增加一個區(qū)域參數(shù) * @param Area_Inf 增加的區(qū)域區(qū)參數(shù)指針 * @return int */ int Add_Area_ToList(Area_Inf_Typedef *Area_Inf) { Area_List_Inf_Typedef *p = Head_Area_List; while(p->next_Area_Inf!=NULL) { p = p->next_Area_Inf; } //先申請鏈表結(jié)構(gòu)體的空間,因為后續(xù)還要繼續(xù)增加 p->next_Area_Inf = (Area_List_Inf_Typedef*)malloc(sizeof(Area_List_Inf_Typedef)); if(p->next_Area_Inf == NULL) return false;//申請不到內(nèi)存,返回失敗 //指向剛剛申請的空間,并為需要存放的動態(tài)區(qū)信息申請對應的內(nèi)存 p = p->next_Area_Inf; p->Area_Inf = (Area_Inf_Typedef*)malloc(sizeof(Area_Inf_Typedef)); if(p->Area_Inf == NULL) { free(p);//由于申請失敗,先前申請的鏈表空間也要釋放 return false; } memcpy(p->Area_Inf,Area_Inf,sizeof(Area_Inf_Typedef)); /*拷貝數(shù)據(jù)*/ p->Area_Inf->Area_Data = (uint8_t*)malloc(Area_Inf->data_len); if(p->Area_Inf->Area_Data == NULL) { free(p->Area_Inf); free(p); return false; } memcpy(p->Area_Inf->Area_Data,Area_Inf->Area_Data,Area_Inf->data_len); //標記這個鏈表的尾部 p->next_Area_Inf=NULL; //添加成功 return true; }
通過PC下發(fā)一個刪除指定ID的區(qū)域命令。
/** * @brief 根據(jù)區(qū)域ID刪除動態(tài)區(qū) * @param num 區(qū)域ID * @return int */ int Delete_Area_Accordingn_ID(int num) { int res = false; Area_List_Inf_Typedef *p = Head_Area_List; while(p->next_Area_Inf!=NULL) { Area_List_Inf_Typedef *temp = p; p = p->next_Area_Inf; if(p->Area_Inf->ID == num)//匹配到對應的值 { temp->next_Area_Inf = p->next_Area_Inf; //釋放內(nèi)存空間 free(p->Area_Inf->Area_Data); free(p->Area_Inf); free(p); p=temp; res = true; } } return res; }
看了上面的驅(qū)動函數(shù),相信大家已經(jīng)明白,大家可以自行編寫一些驅(qū)動,下面我實現(xiàn)的三個簡單函數(shù)。
/** * @brief 根據(jù)區(qū)域ID找到鏈表 * @param data_p 鏈表指針 * @param num 區(qū)域ID編號 * @return int */ int Find_Area_According_ID(Area_Inf_Typedef **data_p,int num) { Area_List_Inf_Typedef *p = Head_Area_List; while(p->next_Area_Inf!=NULL) { p = p->next_Area_Inf; if(p->Area_Inf->ID == num)//匹配到對應的值 { *data_p = p->Area_Inf; return true; } } return false; } /** * @brief 刪除所有區(qū)域 * */ int Delete_All_Area(void) { int res = false; Area_List_Inf_Typedef *p = Head_Area_List; while(p->next_Area_Inf!=NULL) { Area_List_Inf_Typedef *temp = p; p = p->next_Area_Inf; temp->next_Area_Inf = p->next_Area_Inf; //釋放內(nèi)存空間 free(p->Area_Inf->Area_Data); free(p->Area_Inf); free(p); p=temp; res = true; } return res; } /** * @brief 打印鏈表信息 * */ void Printf_Area_Inf(void) { int i=0; Area_List_Inf_Typedef *p = Head_Area_List; printf("list ID X Y Width Height Area_Data\r\n"); while(p->next_Area_Inf!=NULL) { p = p->next_Area_Inf; printf(">
下面編寫一個測試函數(shù),可以測試,鏈表的初始化,增加一個區(qū)域,刪除指定區(qū)域,根據(jù)ID返回區(qū)域信息,刪除所有區(qū)域接口。
/** * @brief 鏈表測試函數(shù) * */ void list_main() { int i,j; Area_Inf_Typedef temp; Area_Inf_Typedef **data_p; data_p = NULL; printf("------------------List test---------------------\r\n"); if(!Area_List_Init( )) { printf("Memory fail..\r\n"); } for(i=0;i<5;i++) { temp.ID = i; temp.X = 5+i; temp.Y = i; temp.Width = 10+i; temp.Height = 10+i; temp.data_len = i+1; temp.Area_Data = (uint8_t*)malloc(temp.data_len+1); for(j=0;j<temp.data_len;j++) { temp.Area_Data[j] = j+0x30; } temp.Area_Data[j] = 0; if(!Add_Area_ToList(&temp)) { printf("Add Area %d Area_Info fail\r\n",i); } } Printf_Area_Inf(); printf("\r\n-------------Delete ID of Area is 3-------------\r\n"); Delete_Area_Accordingn_ID(3); Printf_Area_Inf(); temp.ID = 9; temp.data_len = 10; temp.Area_Data = (uint8_t*)malloc(temp.data_len+1); for(j=0;j<temp.data_len;j++) { temp.Area_Data[j] = j+0x30; } temp.Area_Data[j] = 0; if(!Add_Area_ToList(&temp)) { printf("Add Area %d info fail\r\n",temp.ID); } printf("\r\n--------------Add ID of Area is 9---------------\r\n"); Printf_Area_Inf(); Find_Area_According_ID(data_p,2); temp.ID = (*data_p)->ID; Delete_All_Area(); printf("\r\n--------------Delete All Area-------------------\r\n"); Printf_Area_Inf(); while(1); }
測試結(jié)果
IAR和keil工程代碼開源地址:
https://github.com/strongercjd/STM32_Linklist
如果大家手中有板子可以調(diào)試,使用串口打印。如果臨時沒有板子可以debug,可以模擬測試,IAR設置如下:
選擇Simulator調(diào)試
以上是“鏈表在STM32中怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
分享題目:鏈表在STM32中怎么用
分享URL:http://muchs.cn/article38/jcjjpp.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護、云服務器、企業(yè)建站、標簽優(yōu)化、、App設計
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)