Linux中的內核鏈表
鏈表中一般都要進行初始化、插入、刪除、顯示、釋放鏈表,尋找節點這幾個操作,下面我對這幾個操作進行簡單的介紹,因為我的能力不足,可能有些東西理解的不夠深入,造成一定的錯誤,請各位博友指出。
A、Linux內核鏈表中的幾個主要函數(下面是內核中的源碼拿出來給大家分析一下)
1)初始化:
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0) // ptr為struct list_head,其中包括兩個指針next和prev,這裏已經可以看出內核鏈表是雙向循環鏈表
2)尾部插入:
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
} //尾部插入,傳入的參數是新節點中的兩個指針和頭結點中的兩個指針
3)頭部插入函數
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
} //頭插入函數,傳入的參數是新節點中的兩個指針和頭結點中的兩個指針
4)刪除節點函數
static inline void list_del(struct list_head *entry) //傳入要刪除節點中的指針域
{
__list_del(entry->prev, entry->next);//兩個參數分別為所刪除節點前一個節點和後一個節點
entry->next = (void *) 0;//刪除節點後置為空
entry->prev = (void *) 0;
}
5)顯示函數(如果要打印出鏈表中的信息的話要自己寫成打印的函數,比如printf,因為這個其實是一個遍歷的函數,沒有顯示的功能)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/* 這個函數用於遍歷鏈表
pos為節點指針,
head是頭結點中的兩個指針的地址
member為各節點中的指針域
*/
6)刪除鏈表
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
//這裏面的pos和n都是list_head指針,n指針是用於在刪除時不讓鏈表斷鏈
7)尋找節點(這也是用的內核中的遍歷函數)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
B.下面來段代碼給大家看看具體的運用方法
#include"kernel.h"
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
typedef struct list_node
{
int data;
struct list_head list;//節點的指針域是被封裝在struct list_head這個結構體內
//這個結構體中包括struct list_head *next,*prev
}*node,node1;
node init_head(node head)//初始化空鏈表
{
head = (node)malloc(sizeof(node1));//為節點分配空間
if(head == NULL)
{
perror("head");
return NULL;
}
INIT_LIST_HEAD(&(head->list));//#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)//調用內核中的初始化函數,傳入的參數是
//節點的中兩個指針,即struct list_head結構體中的兩個指針
return head;
}
node insert_tail(node head,int data)//尾部插入函數
{
node new = (node)malloc(sizeof(node1));//為新節點分配空間
if(new == NULL)//判斷一下分配空間是否成功
{
perror("new:");
return NULL;
}
new->data = data;
list_add_tail(&(new->list),&(head->list));//調用內核中的從尾部插入的函數,傳入的參數為新節點中的兩個指針
//和頭結點中的兩個指針
return 0;
}
head_insert_node(node head,int data)//頭插入函數
{
node new;//創建一個新節點
new = (node)malloc(sizeof(node1));//為新節點分配空間
if(new == NULL)//判斷一下分配空間是否成功
{
perror("new:");
return 0;
}
new->data = data;
list_add(&(new->list),&(head->list));//調用內核中從頭插入的函數,傳入的參數為新節點的兩個指針和頭結點的兩個指針
return 0;
}
node search_node(node head,int data)//尋找節點函數
{
node p = NULL;
list_for_each_entry(p,&(head->list),list) //內核中的遍歷函數
{
if(p->data == data) //p即為需要找的節點
{
printf("found the data:%d\n",p->data);
goto OK;
}
}
puts("not found the data!");
return NULL;
OK:
return p;
}
int show_node(node tmp)
{
if(tmp == NULL)
{
puts("tmp is NULL!");
return -1;
}
printf("the data is %d\n",tmp->data);
return 0;
}
int delete_node(node head,int data)
{
node p = NULL;
list_for_each_entry(p,&(head->list),list)
{
if(p->data == data)
{
printf("found the data which you want to delete!\n");
goto f;
}
}
f:
list_del(&(p->list));
free(p);
return 0;
}
int show_list(node head)
{
node p = NULL;
list_for_each_entry(p,&(head->list),list)
{
printf("data:%d\n",p->data);
}
return 0;
}
int delete_list(node head)//刪除鏈表函數
{
node p,q;
list_for_each_entry_safe(p,q,&(head->list),list)//這是內核中的安全刪除函數
{
list_del(&(p->list));
free(p);
}
list_del(&(head->list));
free(head);
return 0;
}
int main(int argc,char **argv)
{
node head;
node tmp;
head = init_head(head);//初始化空鏈表函數
insert_tail(head,45);//從末尾插入函數
insert_tail(head,55);
insert_tail(head,65);
head_insert_node(head,75);//從頭插入函數
show_list(head); //顯示鏈表函數
tmp = search_node(head,55);//尋找結點函數
show_node(head);
delete_node(head,55);
//show_list(head);
delete_list(head);//刪除鏈表函數
return 0;
}
Linux中的內核鏈表