<---百草枯--->
qq--916923477--maooam
内核链表
1、内核链表是一个双向循环的链表,它的结构是:struct list_head list;它的每一个节点都与普通的链表的节点完全不一样,它是由一个大的结构体和里面有一个小的结构体组成,即:
![]() |
其中一个小的结构体list为prev和next,而大结构体是整一个节点的内容。
先定义一下在下面要用到的变量:
struct kool_list { int to; struct list_head list; int from; };
struct kool_list *tmp; struct list_head *pos, *q; unsigned int i;
struct kool_list mylist;
|
2、内核链表的函数:
2.1初始化的函数:
INIT_LIST_HEAD (&mylist.list); /*初始化链表头 */
|
2.2在内核链表中插入节点
tmp = (struct kool_list *) malloc (sizeof (struct kool_list));
/* 或者INIT_LIST_HEAD(&tmp->list); */ printf ("enter to and from:"); scanf ("%d %d", &tmp->to, &tmp->from);
list_add (&(tmp->list), &(mylist.list)); /* 也可以用list_add_tail() 在表尾增加元素 */
|
2.3遍历内核链表
list_for_each (pos, &mylist.list) {
/* 在这里 pos->next 指向next 节点, pos->prev指向前一个节点.这里的节点是 struct kool_list类型. 但是,我们需要访问节点本身,
而不是节点中的list字段,宏list_entry()正是为此目的。 */
tmp = list_entry (pos, struct kool_list, list);
printf ("to= %d from= %d\n", tmp->to, tmp->from);
|
2.4删除某个节点
/*现在,我们可以释放 kool_list节点了.我们本可以调用 list_del()删除节点元素,
* 但为了避免遍历链表的过程中删除元素出错,因此调用另一个更加安全的宏 list_for_each_safe(),
* 具体原因见后面的分析*/
printf ("deleting the list using list_for_each_safe()\n"); list_for_each_safe (pos, q, &mylist.list) { tmp = list_entry (pos, struct kool_list, list); printf ("freeing item to= %d from= %d\n", tmp->to, tmp->from); list_del (pos); free (tmp);
}
|
3、实例代码:
#include <stdio.h> #include <stdlib.h>
#include "list.h"
struct kool_list { int to; struct list_head list; int from; };
int main (int argc, char **argv) {
struct kool_list *tmp; struct list_head *pos, *q; unsigned int i;
struct kool_list mylist; INIT_LIST_HEAD (&mylist.list); /*初始化链表头 */
/* 给mylist增加元素 */ for (i = 5; i != 0; --i) { tmp = (struct kool_list *) malloc (sizeof (struct kool_list));
/* 或者INIT_LIST_HEAD(&tmp->list); */ printf ("enter to and from:"); scanf ("%d %d", &tmp->to, &tmp->from);
list_add (&(tmp->list), &(mylist.list)); /* 也可以用list_add_tail() 在表尾增加元素 */ } printf ("\n");
printf ("traversing the list using list_for_each()\n"); list_for_each (pos, &mylist.list) {
/* 在这里 pos->next 指向next 节点, pos->prev指向前一个节点.这里的节点是 struct kool_list类型. 但是,我们需要访问节点本身,
而不是节点中的list字段,宏list_entry()正是为此目的。 */
tmp = list_entry (pos, struct kool_list, list);
printf ("to= %d from= %d\n", tmp->to, tmp->from);
} printf ("\n"); /* 因为这是循环链表,也可以以相反的顺序遍历它, *为此,只需要用'list_for_each_prev'代替'list_for_each',
* 也可以调用list_for_each_entry() 对给定类型的节点进行遍历。 * 例如: */ printf ("traversing the list using list_for_each_entry()\n"); list_for_each_entry (tmp, &mylist.list, list) printf ("to= %d from= %d\n", tmp->to, tmp->from); printf ("\n");
/*现在,我们可以释放 kool_list节点了.我们本可以调用 list_del()删除节点元素,
* 但为了避免遍历链表的过程中删除元素出错,因此调用另一个更加安全的宏 list_for_each_safe(),
* 具体原因见后面的分析*/
printf ("deleting the list using list_for_each_safe()\n"); list_for_each_safe (pos, q, &mylist.list) { tmp = list_entry (pos, struct kool_list, list); printf ("freeing item to= %d from= %d\n", tmp->to, tmp->from); list_del (pos); free (tmp); }
return 0; }
|
4、附加:
当链表又被删除节点(list_del()函数调用)后,遍历链表的操作只能用使用list_for_each_safe(p, n, head) 和list_for_each_entry_safe(p,n head, list),但要注意,二者使用的时候,里面的临时变量n指针所指向的 结构体是不一样的(具体参考:inc/cli_info.h中的cli_info_list_find_by_fd()函数,这个函数写了2种表达方式):
#if 1 //you can choose this expression or the next for list all of the elements. struct cli_info *n; list_for_each_entry_safe(pnode,n, &head->list, list) { #else struct list_head *p, *n; list_for_each_safe(p, n, &head->list) { pnode = list_entry(p,struct cli_info,list); #endif
|