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中。差不多知道这些也够用了,等碰到问题了,再学习。

  • 相关阅读:
    Coursera机器学习week11 单元测试
    关于 TypeReference 的解释
    getModifiers 方法解释。
    instanceof isInstance isAssignableFrom 比较
    elasticsearch 基础 语法总结
    kibana 启动 关闭 和进程查找
    MD5 SHA1 SHA256 SHA512 SHA1WithRSA 的区别
    spring boot 项目 热启动
    java zip 压缩文件
    Packet for query is too large (1660 > 1024). You can change this value on the server by setting the max_allowed_packet' variable.
  • 原文地址:https://www.cnblogs.com/wuyida/p/6300048.html
Copyright © 2011-2022 走看看