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("创建链表头节点失败!
");
    }
    //添加新节点
    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失败!
");
        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失败!
");
        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("查询节点失败
");
        }
        else{
            temp2 = container_of(temp, Student1, mynode);
            printf("学生的编号:%d;学生的姓名%s
", 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("节点删除失败!
");
        }
        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
", 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
", 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
", 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
", 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
", 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("链表为空,无法在指定位置插入节点
", 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
", 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
", 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
", ERRO_MSG);
        return ERRO_MSG;
    }
    return ERRO_MSG;
}

原文地址:https://www.cnblogs.com/zhanggaofeng/p/5569603.html