<---百草枯--->
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
|