通用鏈表 - 如何寫出高質量代碼
-
在項目開發的過程中,我們不可避免的遇到一些在編譯前無法知道信息大小的場景,需要使用鏈表存儲。比如解TS文件流時需要解出pat表,pmt表,sdt表,eit表等。但是每一種表所組成的鏈表結點信息都不一樣,通用做法是每一個表都需要寫對應的鏈表插入函數,打印函數和刪除函數。這樣會導致擁有大量的重複相似代碼,爲了提高鏈表函數的利用率,我們在下面引入通用鏈表的概念
-
所謂通用鏈表,其思想是利用void *萬能指針實現,將數據域設置爲指針,再調用時指向存放數據的結構體地址,從而達到不同類型結點使用同一套鏈表插入,打印,刪除等操作。
-
代碼示例
-
link_list.h
-
lin_list.h提供了三個鏈表函數,分別爲添加鏈表結點,打印鏈表,銷燬鏈表,其中打印鏈表用到回調函數。如果不是很瞭解回調函數可以看https://blog.csdn.net/MOSHIWANGJUE/article/details/105554956
/************************************************************************* * Filename : link_list.h * Description : Provide interfaces for external access * Version : 1.0 * History : * hehejun 2020-5-5 Create **************************************************************/ #ifndef _LINK_LIST_H_ #define _LINK_LIST_H_ typedef struct list { void *data; struct list *next; }GENAL_LIST; GENAL_LIST *append_link_list(GENAL_LIST *link_list, int data_size, void *add_node); void print_link_list(GENAL_LIST *link_list, void(*handle)(const void *)); void destory_link_list(GENAL_LIST *link_list); #endif
-
link_list.c
-
插入鏈表使用的是頭插法,將需要傳入值外部賦值後傳入,通過data指針指向其地址,達到實現通用插入的效果
/************************************************************************* * Filename : link_list.c * Description : create general_link_list function * Version : 1.0 * History : * hehejun 2020-5-5 Create **************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "link_list.h" /************************************************************** * Function Name : append_link_list * Description : insert new node to link_list * Parameters : * link_list -- need link_list deal with * data_size -- need insert node data_size * add_node -- need insert node * Returns : link_list header pointer **************************************************************/ GENAL_LIST *append_link_list(GENAL_LIST *link_list, int data_size, void *add_node) { GENAL_LIST *new_node = NULL; if ((0 == data_size ) || (NULL == add_node)) //Parameter validity check { printf("input parameters illegal\n"); return NULL; } new_node = (GENAL_LIST *)malloc(data_size); //mallloc insert_node if (NULL == new_node) { printf("no enough memory to malloc\n"); } new_node->data = add_node; new_node->next = link_list; return new_node; } /************************************************************** * Function Name : print_link_list * Description : printf link_list node value one by one * Parameters : * link_list -- need link_list deal with * handle -- callback function's pointer * Returns : NULL **************************************************************/ void print_link_list(GENAL_LIST *link_list, void(*handle)(const void *)) { GENAL_LIST *current_node = link_list; if (NULL == link_list) //Parameter validity check { printf("link_list is NULL\n"); return ; } while(NULL != current_node) { handle(current_node->data); current_node = current_node->next; } } /************************************************************** * Function Name : destory_link_list * Description : free link_list node * Parameters : * link_list -- need link_list deal with * Returns : NULL **************************************************************/ void destory_link_list(GENAL_LIST *link_list) { GENAL_LIST *need_delete_node = NULL; while (NULL != link_list) { need_delete_node = link_list; link_list = link_list->next; free(need_delete_node); } }
-
main.c
-
分別定義兩種結構體結點的鏈表,分別爲pat表和個人信息表,使用通用鏈表的三個函數進行操作
#include <stdio.h> #include <stdlib.h> #include "link_list.h" typedef struct Node { unsigned int program_number; unsigned int program_pid; }DATA_NODE; typedef struct persion { char *name; unsigned int age; char *university; }PERSION; void print_node(const void *p); void print_persion(const void *p); int main(int arg, char *argv[]) { GENAL_LIST *pat_table = NULL; GENAL_LIST *persion_table = NULL; DATA_NODE node1; DATA_NODE node2; PERSION node3; PERSION node4; node1.program_number = 0x00; node1.program_pid = 0x12; node2.program_number = 0x01; node2.program_pid = 0x4e; node3.name = "zhangsan"; node3.age = 23; node3.university = "jiangxi university"; node4.name = "lisi"; node4.age = 22; node4.university = "jiangxi university"; pat_table = append_link_list(pat_table, sizeof(DATA_NODE), &node1); pat_table = append_link_list(pat_table, sizeof(DATA_NODE), &node2); print_link_list(pat_table, print_node); persion_table = append_link_list(persion_table, sizeof(PERSION), &node3); persion_table = append_link_list(persion_table, sizeof(PERSION), &node4); print_link_list(persion_table, print_persion); destory_link_list(pat_table); pat_table = NULL; destory_link_list(persion_table); persion_table = NULL; return 0; } void print_node(const void *p) { DATA_NODE *q = (DATA_NODE *)p; printf("program_number %x\n", q->program_number); printf("program_pid %x\n", q->program_pid); } void print_persion(const void *p) { PERSION *q = (persion *)p; printf("persion.name : %s\n", q->name); printf("persion.age : %d\n", q->age); printf("persion.university : %s\n", q->university); }
-
編譯運行
-
-
總結:通用鏈表可以實現對結點結構不同的鏈表進行操作,達到省略重複相似代碼的效果,提高代碼質量,但同時由於使用void *萬能指針,在程序控制方面需要細心。