zoukankan      html  css  js  c++  java
  • 和菜鸟一起学linux之双向链表list head的简单实例

           经常在linux内核中看到list head这个链表头,有时候看着也不是很懂,很早就打算拎出来好好理解理解了。这次趁着编写SDK后有点小空闲,就拿出来晒晒吧。

           简单的链表实现

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct list_head
    {
           struct list_head *next, *prev;
    };
    
     
    
    #define INIT_LIST_HEAD(ptr) do{ \
           (ptr)->next = (ptr); (ptr)->prev = (ptr); \
           }while(0)
          
    
    #define list_for_each(pos, head) \
          for (pos = (head)->next; pos != (head); pos = pos->next) 
    
    #define offsetof(TYPE, MEMBER) ((size_t)& ((TYPE *)0)->MEMBER)     
    
    #define container_of(ptr, type, member) ({\
           const typeof( ((type *)0)->member ) *__mptr = (ptr);\
              (type*)((char *)__mptr - offsetof(type,member));})  
    
     
    
    #define list_entry(ptr, type, member) \
           container_of(ptr, type, member)
    
     
    
    #define list_for_each_safe(pos, n, head) \
          for (pos = (head)->next, n = pos->next; pos != (head); \
                  pos = n, n = pos->next)
     
    
    static inline void __list_del(struct list_head * prev, struct list_head * next)
    {
           next->prev = prev;
           prev->next = next;
    }
    
     
    
    static inline void __list_del_entry(struct list_head *entry)
    {
           __list_del(entry->prev, entry->next);
    }
    
    static inline void list_del_init(struct list_head *entry)
    {
          __list_del_entry(entry);
          INIT_LIST_HEAD(entry);
    }
          
    static inline void __list_add(struct list_head *new1,
                               struct list_head *prev,
                              struct list_head *next)
    {
    
           next->prev = new1;
           new1->next = next;
           new1->prev = prev;
           prev->next = new1;
    
    } 
    
    static inline void list_add(struct list_head *new1, struct list_head *head)
    {
           __list_add(new1, head, head->next);
    
    } 
    
    struct person
    {
           int age;
           int weight;
           struct list_head list; 
    };
    
    int main(void)
    {
           struct person *tmp;
           struct list_head *pos, *n;
           int age_i, weight_j;
           struct person person_head;
    
           INIT_LIST_HEAD(&person_head.list);
        
           for(age_i = 10, weight_j = 35; age_i < 40; age_i += 5, weight_j +=5)
           {
                  tmp = (struct person *)malloc(sizeof(struct person));
                  tmp->age = age_i;
                  tmp->weight = weight_j;
                  list_add(&(tmp->list), &person_head.list);
           }     
    
           printf("\n");
    
           printf("============ print the list =============\n");
    
           list_for_each(pos, &person_head.list)
           {
                  tmp = list_entry(pos, struct person, list);
                  printf("age:%d,      weight:    %d \n", tmp->age, tmp->weight);
           }
           printf("\n");              
    
           printf("======== print list after delete a node which age is 15 =======\n");
    
           list_for_each_safe(pos, n, &person_head.list)
           {
                  tmp = list_entry(pos, struct person, list);
                  if(tmp->age== 15)
                  {
                         list_del_init(pos);
                         free(tmp);
                  }
           }
    
           list_for_each(pos, &person_head.list)
           {
                  tmp = list_entry(pos, struct person, list);
                  printf("age:%d,      weight:%d\n", tmp->age, tmp->weight);
           }
    
           return 0;
    }
    
    


     

    下面还是分析下这个list head中的各个函数和宏定义吧。

    1、  INIT_LIST_HEAD

    这个就是初始化链表头了,指针都指向本身

    2、  list_for_each

    这个就是遍历了函数,看看函数原型就知道是for循环了。和一般的单链表的遍历没什么多大区别。

    3、  container_of

    这个在以前的blog中有写用法

    4、  list_entry

    这个就是上面的container_of了,具体的含义就是根据list这个链表头的指针得到整个定义的结构体的指针。

    5、  list_for_each_safe

    这个和list_for_each的功能其实是一样的,只是他多了一个n中间变量,因为可以pos这个指针被删除了,pos的指向就会变了,而引入了n这个变量,那么就不会出错了,就安全了。所以这里多了一个safe

    6、  list_del_init

    删除一个节点

    7、  list_add

    插入一个节点

     

         函数主要的功能也讲完了,实现方法也可以根据main函数看出来。这里只是用了一部分的函数和宏,具体的可以参照linux/list.h中。差不多知道这些也够用了,等碰到问题了,再学习。

  • 相关阅读:
    JS组件系列——自己动手扩展BootstrapTable的treegrid功能
    JS组件系列——自己动手封装bootstrap-treegrid组件
    JS组件系列——又一款MVVM组件:Vue(二:构建自己的Vue组件)
    使用Advanced Installer制作IIS安装包(二:配置安装包依赖项和自定义dll)
    使用Advanced Installer制作IIS安装包(一:配置IIS和Web.config)
    C#组件系列——又一款日志组件:Elmah的学习和分享
    推荐一款带暂停功能的轮播组件,不要谢我,我叫红领巾!
    JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)
    CSS系列——前端进阶之路:初涉Less
    MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300048.html
Copyright © 2011-2022 走看看