暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Linux内核数据结构之链表

韭黄炒鸡蛋 2018-10-15
352

内容目录

0、前言1、链表介绍2、链表的实现3、测试例子4、运行结果

0、前言

在进行Linux设备驱动开发时,经常会看到链表的使用,链表是一种常见的数据结构,内核中广泛使用链表是因为:

a. 可拓展性

b. 封装

内核源码的可拓展较较好理解,内核庞大但一直在更新,代码不可写死,需要可修改删除,链表很好的符合这个特性。

1、链表介绍

根据链个数分为单链表、双链表,根据是否循环分为单向链表和循环链表。通常定义定义链表结构如下:

typedef struct node
{

     ElemType data;      //数据域
     struct node *next;  //指针域
}node, *list;

其中,双向循环链表如下图所示:

内核的链表结构也是双向循环链表,但内核的链表不包括数据域,如下图所示:

链表结构定义如下:

struct list_head {
    struct list_head *next, *prev;
};

不包含数据域

例如,定义一个student 链表

struct student {
    char name[32];
    int id;
    struct list_head list;  //链表节点
};

Student 通过list进行链表操作

2、链表的实现

a. 创建链表
  a) 使用宏

LIST_HEAD(name);    //创建一个名为name的链表,实质上是创建一个头节点,头节点代表一个链表

struct list_head name = LIST_HEAD_INIT(name);

b. 添加节点

i. void list_add(struct list_head *new,struct list_head *head);//添加到首节点前面
ii. void list_add_tail(struct list_head *new, struct list_head *head);//添加到尾节点后面

new是要添加的节点,head是被添加的链表

c. 删除节点

a) void list_del(struct list_head *entry);
b) void list_del_init(struct list_head *entry);

参数entry指向要删除的节点,推荐使用 list_del_init更为安全

d. 对链表的判断
a) 判断节点是否是尾节点:

i. int list_is_last(struct list_head *list,struct list_head *head)

b) 判断链表是否为空:

i. int list_empty(struct list_head *head)

c) 判断链表是否只有一个元素

i. int list_is_singular(struct list_head *head)

e. 遍历链表

list_for_each_entry(pos, head, member) //该宏的展开是一个for循环

f. 替换节点

void list_replace(struct list_head *old,struct list_head *new)
void list_replace_init(struct list_head *old,struct list_head *new)

g. 移动节点

void list_move(struct list_head *list, struct list_head *head)
void list_move_tail(struct list_head *list,struct list_head *head)

移动:从链表中删除,插入一个新的链表中

3、测试例子

代码:
list.h    (包含各函数实现)
Student.c

再此给出student.c的代码

/*
 * student.c
 *
 *  Created on: 2018.10.14
 *  
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "list.h"


struct list_head student_list;//创建链表,链表名是student_list
struct list_head *pos; 
LIST_HEAD(student_list);

/* 定义学生的数据类型 */
struct student {
    char name[32];
    int id;
    struct list_head list;
};

int main(int argc, char **argv)
{
    /* 判断链表是否为空链表 */
    if(list_empty(&student_list)) 
        printf("student_list is empty!\n");
    else
        printf("student_list is not empty!\n");

    /* 向链表中添加节点 */
    struct student *one = (struct student *)malloc(sizeof(struct student));
    strcpy(one->name,"zhangsan");
    one->id = 1;
    list_add(&(one->list),&student_list);      //将one 添加到链表student_list中
    one = (struct student *)malloc(sizeof(struct student));
    strcpy(one->name,"lisi");
    one->id = 2;
    list_add_tail(&(one->list),&student_list);//添加到链表student_list的尾部 

    /* 遍历链表 */
    list_for_each(pos,&student_list)        
    {
        one=list_entry(pos,struct student ,list);
        printf(" ID: %d\t name:%s\n",one->id,one->name); 
    }

    /* 删除一个节点 */
    list_del_init(&(one->list));    

    /* 再次遍历链表 */
    printf("del one node ,list is:\n");
    list_for_each(pos,&student_list)      
    {
        one=list_entry(pos,struct student ,list);
        printf(" ID: %d\t name:%s\n",one->id,one->name); 
    }

    /* 再次判断链表是否为空 */
    if(list_empty(&student_list))
        printf("list is empty!\n");
    else
        printf("list is not empty!\n");

    return 0;

}

4、运行结果


文章转载自韭黄炒鸡蛋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论