C语言 Linux内核链表(企业级链表)

//Linux内核链表(企业级链表)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define offscfof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr,type,member) (type *)((char *)ptr-offscfof(type,member))

typedef struct _node{
    struct _node *pNext;
}Node;

typedef struct _student1{
    int num;
    char name[20];
    Node mynode;
}Student1;
//说明:结构体也可以写成以下模式
//typedef struct _student1{
//    Node mynode;
//    int num;
//    char name[20];
//}Student1;
//这样一来,就不需要计算链表节点属性在结构体中的偏移量了,简单实用
//我之所以写的复杂是为了深刻理解其原理

//创建链表
int SList_Create(Node **pout/*out*/);
//获取链表长度
int Get_List_Len(Node *pin/*in*/);
//查找指定位置节点
int FindNode(Node *pin/*in*/, Node **pdel/*out*/, int pos/*in*/);
//插入指定位置节点
int InsertOption(Node *pin/*in*/, Node *pnode/*in*/, int pos/*in*/);
//删除指定节点
int RemoveNode(Node *pin/*in*/, Node **pdel/*out*/, int pos/*in*/);

void main(){
    //创建链表指针
    Node *phead;
    int i = 0,j=0;
    int ret = SList_Create(&phead);
    //说明:为什么我要创建一个无用的头节点
    //理由①:不创建一个头节点,那么初始化函数SList_Create()就没有必要存在
    //理由②:插入第一个节点的时候无法插入,以为没有头结点,所以插不进去第一个节点(这是主要理由)
    if (ret!=0)
    {
        printf("创建链表头节点失败!\n");
    }
    //添加新节点
    Student1 *pa = (Student1 *)malloc(sizeof(Student1));
    pa->num = 1;
    strcpy(pa->name, "小米");
    pa->mynode.pNext = NULL;
    ret=InsertOption(phead, &pa->mynode, Get_List_Len(phead));
    if (ret != 0)
    {
        printf("添加新节点a失败!\n");
        goto END;
    }
    Student1 *pb = (Student1 *)malloc(sizeof(Student1));
    pb->num = 1;
    strcpy(pb->name, "小明");
    pb->mynode.pNext = NULL;
    ret = InsertOption(phead, &pb->mynode, Get_List_Len(phead));
    if (ret != 0)
    {
        printf("添加新节点b失败!\n");
        goto END;
    }
    //打印出所有的节点
    for (j = 0; j < Get_List_Len(phead); j++)
    {
        Node *temp = NULL;
        Student1 *temp2 = NULL;
        FindNode(phead, &temp, j);
        if (temp==NULL)
        {
            printf("查询节点失败\n");
        }
        else{
            temp2 = container_of(temp, Student1, mynode);
            printf("学生的编号:%d;学生的姓名%s\n", temp2->num, temp2->name);
        }

    }
END:
    //删除所有链表节点
    while (Get_List_Len(phead)){
        Node *temp = NULL;
        Student1 *temp2 = NULL;
        RemoveNode(phead, &temp, 0);
        temp2 = container_of(temp, Student1, mynode);
        if (temp == NULL)
        {
            printf("节点删除失败!\n");
        }
        else{
            if (temp2 != NULL)
            {
                free(temp2);
            }
        }
    }
    //释放头节点
    if (phead==NULL)
    {
        free(phead);
    }
    system("pause");
}

//创建链表(顺序创建链表)
int SList_Create(Node **pout/*out*/){
    int ERRO_MSG = 0;
    if (pout==NULL)
    {
        ERRO_MSG = 1;
        printf("pout==NULL erro msg:%d\n", ERRO_MSG);
        return ERRO_MSG;
    }
    Node *pM = (Node *)malloc(sizeof(Node));
    pM->pNext = NULL;
    *pout = pM;
    return ERRO_MSG;
}

//获取链表长度
int Get_List_Len(Node *pin/*in*/){
    Node *pHead = NULL, *pCurrent = NULL;
    int index = 0;
    pCurrent = pin->pNext;
    while (pCurrent){
        pCurrent = pCurrent->pNext;
        index++;
    }
    return index;
}

//查找指定位置节点
int FindNode(Node *pin/*in*/, Node **pnode/*out*/, int pos/*in*/){
    int ERRO_MSG = 0;
    if (pin == NULL || pnode == NULL)
    {
        ERRO_MSG = 1;
        printf("pin == NULL || pnode==NULL erro msg:%d\n", ERRO_MSG);
        return ERRO_MSG;
    }
    Node *pHead = NULL, *pCurrent = NULL, *pMalloc = NULL, *pPrior = NULL;
    pCurrent = pPrior = pin->pNext;
    if (pCurrent==NULL)
    {
        ERRO_MSG = 2;
        printf("链表中暂时没有数据  erro msg:%d\n", ERRO_MSG);
        return ERRO_MSG;
    }
    int index = 0;
    while (pCurrent){
        if (index==pos)
        {
            *pnode = pCurrent;
            break;
        }
        pPrior = pCurrent;
        pCurrent = pCurrent->pNext;
        index++;
    }
    if (*pnode==NULL)
    {
        ERRO_MSG = 3;
        printf("链表中没有找到该节点  erro msg:%d\n", ERRO_MSG);
        return ERRO_MSG;
    }
    return ERRO_MSG;
}

//插入指定位置节点
int InsertOption(Node *pin/*in*/, Node *pnode/*in*/, int pos/*in*/){
    int ERRO_MSG = 0;
    if (pin == NULL || pnode==NULL)
    {
        ERRO_MSG = 1;
        printf("pin == NULL || pnode==NULL erro msg:%d\n", ERRO_MSG);
        return ERRO_MSG;
    }
    Node *pHead = NULL, *pCurrent = NULL, *pMalloc = NULL,*pPrior=NULL;
    pHead = pPrior = pin;
    pCurrent = pin->pNext;
    pMalloc = pnode;
    if (pCurrent==NULL)
    {
        if (pos==0)
        {
            pHead->pNext = pMalloc;
            return ERRO_MSG;
        }
        else{
            ERRO_MSG = 2;
            printf("链表为空,无法在指定位置插入节点\n", ERRO_MSG);
            return ERRO_MSG;
        }
    }
    int index = 0;
    while (pCurrent){
        if (pos == index)
        {
            pPrior->pNext = pMalloc;
            pMalloc->pNext = pCurrent;
            return ERRO_MSG;
        }
        pPrior = pCurrent;
        pCurrent = pCurrent->pNext;
        index++;
    }
    pPrior->pNext = pMalloc;
    return ERRO_MSG;
}

//删除指定节点
int RemoveNode(Node *pin/*in*/, Node **pdel/*out*/, int pos/*in*/){
    int ERRO_MSG = 0;
    if (pin == NULL || pdel==NULL)
    {
        ERRO_MSG = 1;
        printf("pin == NULL || pdel==NULL erro msg:%d\n", ERRO_MSG);
        return ERRO_MSG;
    }
    Node *pHead = NULL, *pCurrent = NULL, *pMalloc = NULL, *pPrior = NULL;
    pHead = pPrior = pin;
    pCurrent = pin->pNext;
    if (pCurrent==NULL)
    {
        ERRO_MSG = 2;
        printf("你要删除的链表为空! erro msg:%d\n", ERRO_MSG);
        return ERRO_MSG;
    }
    int index = 0, flag = 0;
    while (pCurrent){
        if (index == pos)
        {
            pPrior->pNext = pCurrent->pNext;
            *pdel = pCurrent;
            break;
        }
        pPrior = pCurrent;
        pCurrent = pCurrent->pNext;
        index++;
    }
    if (*pdel==NULL)
    {
        ERRO_MSG = 3;
        printf("链表中没有该位置的节点! erro msg:%d\n", ERRO_MSG);
        return ERRO_MSG;
    }
    return ERRO_MSG;
}

时间: 2024-10-08 15:00:41

C语言 Linux内核链表(企业级链表)的相关文章

Linux内核之旅 链表实现

1 #include "stdio.h" 2 #include "stdlib.h" 3 4 struct list_head{ 5 struct list_head *prev; 6 struct list_head *next; 7 }; 8 9 struct task{ 10 int member; 11 struct list_head list; 12 }; 13 14 #define list_entry(ptr,member,type) 15 ((ty

[原理分析]linux内核中的链表原理实践

摘要: 本文根据linux内核的链表定义,尝试自己来完成相关的接口设计,并且构建测试用例,来体会下链表接口的用法. 正文: 首先来看下linux内核提供的链表接口大致如下: struct head_node{ struct head_node* pre; struct head_node* next; }; 即节点中只有两个指针:一个指向前一个元素,一个指向后一个元素:假设我们现在要使用该接口,跟一个int值联合在一起形成数据节点,那么存在两种可能的方式: case1: typedef stru

AT&amp;T汇编语言与GCC内嵌汇编,Linux内核数据结构之链表

最近在看<Linux内核源代码情景分析>,作者毛德操.书中刚开始介绍了AT&T汇编语言与GCC内嵌汇编,以及Linux内核数据结构之链表.可惜书中介绍的不够全面.因为推荐大家阅读下面两篇文章.很不错. AT&T汇编语言与GCC内嵌汇编:http://grid.hust.edu.cn/zyshao/Teaching_Material/OSEngineering/Chapter2.pdf. Linux内核数据结构之链表:http://www.cnblogs.com/Anker/p/

Linux内核数据结构之链表

与经典双向链表比较 ??经典双向链表如图.其中有一个pre指针和一个next指针,数据是在链表的节点内. ??内核链表如图.每一个链表节点内只有一个pre指针和一个next指针,整个链表节点嵌入到了一个需要使用链表的结构体内. 内核链表介绍 ??内核链表节点结构体定义如图.其中next指针指向下一个链表节点,prev指针指向前一个链表节点. ??前面已经说过,内核链表节点是嵌入到数据节点内的,那么就产生了一个问题,如何访问到链表所在结构体的指针呢? ??内核链表中通过list_entry宏来访问

[原理分析]linux内核中的链表原理实践[2]

摘要: 本文过程化的演进方式,将自己写的链表结构慢慢地演化到类似linux内核链表的实现. 正文: 在本系列1中,如果将data_node中的信息调换一下,也即value放在前面,将head_node信息放在后面,那么节点数据就不能正常输出. typedef struct data_node{ int value; head_node h; }data_node; 要查找原因,主要还是看list_value函数的实现: void list_value(data_node* d) { data_n

[原理分析]linux内核中的链表原理实践[3]

摘要: 本文的第[一,二]系列主题虽然是链表操作,内容还是指针的操作,本文通过链表实例来阐述下指针操作.不仅仅涉及到数据节点指针,也还涉及到函数指针,最后还涉及基于指针的函数体优化. 正文: 本文主要阐述链表中的节点删除操作,并且在删除过程中使用回调函数.回调函数本身也很简单,就是判断当前节点中数据的奇性或者偶性,来判断是否删除该数据节点. #include "stdafx.h" #include <memory> typedef struct node{ int valu

例说Linux内核链表(一)

介绍 众所周知,Linux内核大部分是使用GNU C语言写的.C不同于其他的语言,它不具备一个好的数据结构对象或者标准对象库的支持.所以可以借用Linux内核源码树的循环双链表是一件很值得让人高兴的事. 在include/linux/list.h文件中用C实现了一个好用的循环链表.它是有效而且易于操作的,否则它也不会被内核使用(译者注:在kernel中大量的使用了循环双链表结构,比如在在进程描述符实体中我们就可以看到很多struct list_head的身影).不管何时,依靠这种结构,在内核中都

Linux内核数据结构——链表

目录 目录 简介 单向链表 双向链表 环形链表 Linux内核中的链表实现 offsetof container_of container_of 第一部分 container_of 第二部分 链表初始化 向链表中增加一个节点 删除节点 移动节点 判断链表是否为空 遍历链表 Demo测试 mlisth mlistc 执行结果 简介 最近在学习Android Binder驱动程序实现的时候,发现里面的数据结构用到了struct list_head.而我google发现struct list_head

linux内核链表的使用

linux内核链表:链表通常包括两个域:数据域和指针域.struct list_head{struct list_head *next,*prev;};include/linux/list.h中实现了一套精彩的链表数据结构.传统的链表指针指向下一个节点的头部.linux链表指针指向下一个指针list_head结构(*next),双向循环.不会随着外部数据的变化而变化,使它具有通用性.? -------------------------------------------------------