原文链接:http://blog.csdn.net/xnwyd/article/details/7359373
Linux内核链表的核心思想是:在用户自定义的结构A中声明list_head类型的成员p,这样每个结构类型为A的变量a中,都拥有同样的成员p,如下:
struct A{
int property;
struct list_head p;
}
其中,list_head结构类型定义如下:
struct list_head {
struct list_head *next,*prev;
};
list_head拥有两个指针成员,其类型都为list_head,分别为前驱指针prev和后驱指针next。
假设:
(1)多个结构类型为A的变量a1...an,其list_head结构类型的成员为p1...pn
(2)一个list_head结构类型的变量head,代表头节点
使:
(1)head.next= p1 ; head.prev = pn
(2) p1.prev = head,p1.next = p2;
(3)p2.prev= p1 , p2.next = p3;
…
(n)pn.prev= pn-1 , pn.next = head
以上,则构成了一个循环链表。
因p是嵌入到a中的,p与a的地址偏移量可知,又因为head的地址可知,所以每个结构类型为A的链表节点a1...an的地址也是可以计算出的,从而可实现链表的遍历,在此基础上,则可以实现链表的各种操作。
下面是从linux内核中移植出来的简单链表,list.h和list.c:
list.h:
1 #ifndef _INIT_LIST_H_ 2 #define _INIT_LIST_H_ 3 4 #ifndef offsetof 5 /* Offset of member MEMBER in a struct of type TYPE. */ 6 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 7 #endif 8 9 struct listnode 10 { 11 struct listnode *next; 12 struct listnode *prev; 13 }; 14 15 #define node_to_item(node, container, member) 16 (container *) (((char*) (node)) - offsetof(container, member)) 17 18 #define list_declare(name) 19 struct listnode name = { 20 .next = &name, 21 .prev = &name, 22 } 23 24 #define list_for_each(node, list) 25 for (node = (list)->next; node != (list); node = node->next) 26 27 #define list_for_each_reverse(node, list) 28 for (node = (list)->prev; node != (list); node = node->prev) 29 30 void list_init(struct listnode *list); 31 void list_add_tail(struct listnode *list, struct listnode *item); 32 void list_remove(struct listnode *item); 33 34 #define list_empty(list) ((list) == (list)->next) 35 #define list_head(list) ((list)->next) 36 #define list_tail(list) ((list)->prev) 37 38 #endif
list.c:
1 #include "list.h" 2 3 void list_init(struct listnode *node) 4 { 5 node->next = node; 6 node->prev = node; 7 } 8 9 void list_add_tail(struct listnode *head, struct listnode *item) 10 { 11 item->next = head; 12 item->prev = head->prev; 13 head->prev->next = item; 14 head->prev = item; 15 } 16 17 void list_remove(struct listnode *item) 18 { 19 item->next->prev = item->prev; 20 item->prev->next = item->next; 21 }
测试代码list_test.c:
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include "list.h" 4 5 #define STUDENT_FREE_MEMORY 6 7 //声明链表节点 8 typedef struct { 9 int id; 10 char *name; 11 struct listnode _list; 12 }student; 13 14 //遍历函数指针 15 typedef void (*student_foreach_fun)(student *stu,void *data); 16 17 18 //声明链表 19 static list_declare(student_list); 20 21 //添加节点 22 int student_add(struct listnode *list,student *stu) 23 { 24 list_init(&stu->_list); 25 list_add_tail(list,&stu->_list); 26 return 0; 27 } 28 29 //删除节点,释放节点空间 30 int student_del(struct listnode *list,int id) 31 { 32 struct listnode *node; 33 student *stu; 34 list_for_each(node,list){ 35 stu = node_to_item(node,student,_list); 36 if(id == stu->id){ 37 printf("list_del, id:%d,name:%s\n",stu->id,stu->name); 38 list_remove(node); 39 #ifdef STUDENT_FREE_MEMORY 40 //释放节点空间 41 free(stu); 42 stu = NULL; 43 #endif 44 return 1; 45 46 } 47 48 } 49 50 return 0; 51 } 52 53 //节点遍历 54 void student_foreach(struct listnode *list,student_foreach_fun fun,void *data) 55 { 56 struct listnode *node; 57 student *stu; 58 list_for_each(node,list){ 59 stu = node_to_item(node,student,_list); 60 fun(stu,data); 61 } 62 63 } 64 65 //打印节点信息 66 void student_print(student *stu,void *data) 67 { 68 printf("id:%d,name:%s\n",stu->id,stu->name); 69 } 70 71 int main() 72 { 73 int i,len; 74 student *stu; 75 char *stu_name[]={"tonny","andy","michael","leslie","john"}; 76 77 78 len = sizeof(stu_name)/sizeof(stu_name[0]); 79 //添加节点 80 for(i=0;i<len;i++){ 81 stu = calloc(1,sizeof(student)); 82 stu->id = i + 1; 83 stu->name = stu_name[i]; 84 85 student_add(&student_list,stu); 86 } 87 88 //打印所有节点 89 student_foreach(&student_list,student_print,(void *)0); 90 91 //删除节点 92 student_del(&student_list,1); 93 student_foreach(&student_list,student_print,(void *)0); 94 95 //删除节点 96 student_del(&student_list,5); 97 student_foreach(&student_list,student_print,(void *)0); 98 99 return 0; 100 101 102 }
Makefile:
1 TARGET=list_test 2 SRC=list_test.c list.c 3 #SRC=$(wildcard *.c) 4 OBJ=$(SRC:.c=.o) 5 CFLAGS=-g -Wall -o 6 7 $(TARGET):$(SRC) 8 gcc $(SRC) $(CFLAGS) $(TARGET) 9 clean: 10 rm $(OBJ) $(TARGET)
时间: 2024-10-15 23:49:02