通用鏈表 - 如何寫出高質量代碼

通用鏈表 - 如何寫出高質量代碼

  • 在項目開發的過程中,我們不可避免的遇到一些在編譯前無法知道信息大小的場景,需要使用鏈表存儲。比如解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 *萬能指針,在程序控制方面需要細心。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章