通用链表 - 如何写出高质量代码

通用链表 - 如何写出高质量代码

  • 在项目开发的过程中,我们不可避免的遇到一些在编译前无法知道信息大小的场景,需要使用链表存储。比如解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 
      #include 
      #include 
      #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 
      #include 
      #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);
      }
      
    • 编译运行

      通用链表 - 如何写出高质量代码_第1张图片

  • 总结:通用链表可以实现对结点结构不同的链表进行操作,达到省略重复相似代码的效果,提高代码质量,但同时由于使用void *万能指针,在程序控制方面需要细心。

你可能感兴趣的:(实习学习,链表,指针,c语言)