C语言链表操作代码

最近闲着没事写了些C标准接口代码 需要的话可以拿着用,我大概测了下功能 没问题,也没有内存泄漏,如果有问题欢迎讨论

链表相关接口实现代码

linklis.c 使用需要替换log接口和返回值接口

/*********************************************************************
 * 版权所有 (c) 2021-2022  axk. 保留所有版权
 * 文件名称: linklist.c
 * 文件描述: 标准链表操作接口实现
 * 作    者: axk
 * 创建日期: 2022/11/21
 * 作    者                 日    期                 版    本          修改摘要
 * axk                   2022/11/21               1.0           文件创建
**********************************************************************/


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include "axk_base_data_type.h"
#include "linklist.h"

/***********************************************************************
 * 函数名称: list_node_free
 * 功能描述: 释放链表节点内存
 * 输    入:node 需要释放的节点
 * 输    出: 无
 * 返 回 值: void
 * 其    他:
 * 日    期: 2022/11/21
 * 作    者: axk
 ***********************************************************************/
void list_node_free(list_node_s_type* node)
{
    
    
    if (NULL != node)
    {
    
    
        if (NULL != node->data)
        {
    
    
            if (NULL != node->free_cb)
            {
    
    
                node->free_cb(node->data);
            }
        }
        node->next = NULL;
        node->prev = NULL;
        free(node);
        node = NULL;
    }
}

/***********************************************************************
 * 函数名称: list_head_insert
 * 功能描述: 向链表头部插入一个节点
 * 输    入:list_head 链表头
 *         data 节点数据内容
 *         free_cb 节点数据free函数 (如果节点释放不需要free数据则填空)
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_head_insert(list_head_s_type* list_head, void* data, list_data_free_cb free_cb)
{
    
    
    list_node_s_type* data_node = NULL;
    list_node_s_type* tmp_node = NULL;
    if (NULL == list_head || NULL == data)
    {
    
    
        AXK_LOGE("list_head or data is NULL!");
        return AXK_ERR_PARAMETER;
    }

    data_node = (list_node_s_type*)malloc(sizeof(list_node_s_type));
    if (NULL == data_node)
    {
    
    
        AXK_LOGE("data_node malloc failed!");
        return AXK_ERR_MALLOC;
    }
    memset(data_node, 0x0, sizeof(list_node_s_type));
    data_node->next = NULL;
    data_node->prev = NULL;
    data_node->data = data;
    data_node->free_cb = free_cb;

    if (NULL != list_head->head)
    {
    
    
        tmp_node = list_head->head;
        list_head->head = data_node;
        data_node->next = tmp_node;
        tmp_node->prev = data_node;
    }
    else
    {
    
    
        list_head->head = data_node;
        list_head->tail = data_node;
    }
    list_head->node_num++;

    return AXK_SUCCESS;
}

/***********************************************************************
 * 函数名称: list_tail_insert
 * 功能描述: 向链表尾部插入一个节点
 * 输    入:list_head 链表头
 *         data 节点数据内容
 *         free_cb 节点数据free函数 (如果节点释放不需要free数据则填空)
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_tail_insert(list_head_s_type* list_head, void* data, list_data_free_cb free_cb)
{
    
    
    list_node_s_type* data_node = NULL;
    list_node_s_type* tmp_node = NULL;

    if (NULL == list_head || NULL == data)
    {
    
    
        AXK_LOGE("list_head or data is NULL!");
        return AXK_ERR_PARAMETER;
    }

    data_node = (list_node_s_type*)malloc(sizeof(list_node_s_type));
    if (NULL == data_node)
    {
    
    
        AXK_LOGE("data_node malloc failed!");
        return AXK_ERR_MALLOC;
    }
    memset(data_node, 0x0, sizeof(list_node_s_type));
    data_node->next = NULL;
    data_node->prev = NULL;
    data_node->data = data;
    data_node->free_cb = free_cb;

    if (NULL != list_head->tail)
    {
    
    
        list_head->tail->next = data_node;
        data_node->prev = list_head->tail;
        list_head->tail = data_node;
    }
    else
    {
    
    
        list_head->head = data_node;
        list_head->tail = data_node;
    }
    list_head->node_num++;

    return AXK_SUCCESS;
}

/***********************************************************************
 * 函数名称: list_head_del
 * 功能描述: 从链表头部删除一个节点
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_head_del(list_head_s_type* list_head)
{
    
    
    list_node_s_type* tmp_node = NULL;
    if (NULL == list_head)
    {
    
    
        AXK_LOGE("list_head is NULL!");
        return AXK_ERR_PARAMETER;
    }

    if (NULL == list_head->head)
    {
    
    
        AXK_LOGE("list_head is empty!");
        return AXK_SUCCESS;
    }

    tmp_node = list_head->head;
    if (NULL != tmp_node->next)
    {
    
    
        list_head->head = tmp_node->next;
        list_head->head->prev = NULL;
    }
    else
    {
    
    
        list_head->tail = NULL;
        list_head->head = NULL;
    }
    list_node_free(tmp_node);
    list_head->node_num--;

    return AXK_SUCCESS;
}

/***********************************************************************
 * 函数名称: list_tail_del
 * 功能描述: 从链表尾部删除一个节点
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_tail_del(list_head_s_type* list_head)
{
    
    
    list_node_s_type* tmp_node = NULL;
    if (NULL == list_head)
    {
    
    
        AXK_LOGE("list_head is NULL!");
        return AXK_ERR_PARAMETER;
    }

    if (NULL == list_head->tail)
    {
    
    
        AXK_LOGE("list_head is empty!");
        return AXK_SUCCESS;
    }

    tmp_node = list_head->tail;
    if (NULL != tmp_node->prev)
    {
    
    
        list_head->tail = tmp_node->prev;
        list_head->tail->next = NULL;
    }
    else
    {
    
    
        list_head->tail = NULL;
        list_head->head = NULL;
    }
    list_node_free(tmp_node);
    list_head->node_num--;

    return AXK_SUCCESS;
}

/***********************************************************************
 * 函数名称: list_del_node_by_data_addrress
 * 功能描述: 根据数据地址从链表删除节点
 * 输    入:list_head 链表头
           data 数据指针
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_del_node_by_data_addrress(list_head_s_type* list_head, void* data)
{
    
    
    list_node_s_type* tmp_node = NULL;
    if (NULL == list_head)
    {
    
    
        AXK_LOGE("list_head is NULL!");
        return AXK_ERR_PARAMETER;
    }

    if (0 == list_head->node_num)
    {
    
    
        AXK_LOGE("list_head is empty!");
        return AXK_ERR_PARAMETER;
    }

    tmp_node = list_head->head;
    while (NULL != tmp_node)
    {
    
    
        if (data == tmp_node->data)
        {
    
    
            if (1 == list_head->node_num)
            {
    
    
                list_head->head = NULL;
                list_head->tail = NULL;
            }
            else if (tmp_node == list_head->tail)
            {
    
    
                list_head->tail = tmp_node->prev;
                tmp_node->prev->next = NULL;
            }
            else if (tmp_node == list_head->head)
            {
    
    
                list_head->head = tmp_node->next;
                tmp_node->next->prev = NULL;
            }
            else
            {
    
    
                tmp_node->next->prev = tmp_node->prev;
                tmp_node->prev->next = tmp_node->next;
            }

            list_head->node_num--;
            list_node_free(tmp_node);
            break;
        }
        tmp_node = tmp_node->next;
    }

    return AXK_SUCCESS;
}

/***********************************************************************
 * 函数名称: list_get_head_node
 * 功能描述: 获取链表头部数据节点
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回头节点指针 失败返回NULL
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
list_node_s_type* list_get_head_node(list_head_s_type* list_head)
{
    
    
    if (NULL == list_head)
    {
    
    
        AXK_LOGE("list_head is NULL!");
        return NULL;
    }

    return list_head->head;
}

/***********************************************************************
 * 函数名称: list_get_tail_node
 * 功能描述: 获取链表尾部数据节点
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回尾部节点指针 失败返回NULL
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
list_node_s_type* list_get_tail_node(list_head_s_type* list_head)
{
    
    
    if (NULL == list_head)
    {
    
    
        AXK_LOGE("list_head is NULL!");
        return NULL;
    }

    return list_head->tail;
}

/***********************************************************************
 * 函数名称: list_destory
 * 功能描述: 链表销毁
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/21
 * 作    者: axk
 ***********************************************************************/
int list_destory(list_head_s_type* list_head)
{
    
    
    list_node_s_type* tmp_node = NULL;
    if (NULL == list_head)
    {
    
    
        AXK_LOGE("list_head is NULL!");
        return AXK_ERR_PARAMETER;
    }

    while (0 != list_head->node_num)
    {
    
    
        tmp_node = list_head->tail;
        if (NULL != tmp_node->prev)
        {
    
    
            list_head->tail = tmp_node->prev;
            list_head->tail->next = NULL;
        }
        else
        {
    
    
            list_head->tail = NULL;
            list_head->head = NULL;
        }
        list_node_free(tmp_node);
        list_head->node_num--;
    }

    return AXK_SUCCESS;
}

/***********************************************************************
 * 函数名称: list_init
 * 功能描述: 链表初始化
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_init(list_head_s_type* list_head)
{
    
    
    if (NULL == list_head)
    {
    
    
        AXK_LOGE("list head is NULL!");
        return AXK_ERR_PARAMETER;
    }
    list_destory(list_head);

    list_head->node_num = 0;
    list_head->head = NULL;
    list_head->tail = NULL;
    return AXK_SUCCESS;
}

链表相关接口头文件

/*********************************************************************
 * 版权所有 (h) 2021-2022  axk. 保留所有版权
 * 文件名称: linklist.h
 * 文件描述: 标准链表操作接口头文件
 * 作    者: axk
 * 创建日期: 2022/11/21
 * 作    者                 日    期                 版    本          修改摘要
 * axk                   2022/11/21               1.0           文件创建
**********************************************************************/
#ifndef __LINK_LIST_H_
#define __LINK_LIST_H_

#include "axk_base_data_type.h"

#ifdef __cplusplus
extern "C" {
    
    
#endif

/****************************LINK_LIST 宏定义 start****************************************************/
/****************************LINK_LIST 宏定义 end****************************************************/

/****************************LINK_LIST 枚举定义 start****************************************************/

/****************************LINK_LIST 枚举定义 end****************************************************/

/****************************LINK_LIST 结构体定义 start****************************************************/
/* 释放节点数据回调函数 */
typedef void (*list_data_free_cb)(void* data);

/* 链表节点结构体 */
typedef struct list_node_s_type
{
    
    
    struct list_node_s_type* next;
    struct list_node_s_type* prev;
    void* data;
    list_data_free_cb free_cb;
} list_node_s_type;

/* 链表头结构体 */
typedef struct list_head_s_type
{
    
    
    int node_num;
    struct list_node_s_type* head;
    struct list_node_s_type* tail;
} list_head_s_type;
/****************************LINK_LIST 结构体定义 end****************************************************/

/****************************LINK_LIST 函数声明 start****************************************************/
/***********************************************************************
 * 函数名称: list_head_insert
 * 功能描述: 向链表头部插入一个节点
 * 输    入:list_head 链表头
 *         data 节点数据内容
 *         free_cb 节点数据free函数 (如果节点释放不需要free数据则填空)
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_head_insert(list_head_s_type* list_head, void* data, list_data_free_cb free_cb);

/***********************************************************************
 * 函数名称: list_tail_insert
 * 功能描述: 向链表尾部插入一个节点
 * 输    入:list_head 链表头
 *         data 节点数据内容
 *         free_cb 节点数据free函数 (如果节点释放不需要free数据则填空)
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_tail_insert(list_head_s_type* list_head, void* data, list_data_free_cb free_cb);

/***********************************************************************
 * 函数名称: list_head_del
 * 功能描述: 从链表头部删除一个节点
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_head_del(list_head_s_type* list_head);

/***********************************************************************
 * 函数名称: list_tail_del
 * 功能描述: 从链表尾部删除一个节点
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_tail_del(list_head_s_type* list_head);

/***********************************************************************
 * 函数名称: list_del_node_by_data_addrress
 * 功能描述: 根据数据地址从链表删除节点
 * 输    入:list_head 链表头
           data 数据指针
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_del_node_by_data_addrress(list_head_s_type* list_head, void* data);

/***********************************************************************
 * 函数名称: list_get_head_node
 * 功能描述: 获取链表头部数据节点
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回头节点指针 失败返回NULL
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
list_node_s_type* list_get_head_node(list_head_s_type* list_head);

/***********************************************************************
 * 函数名称: list_get_tail_node
 * 功能描述: 获取链表尾部数据节点
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回尾部节点指针 失败返回NULL
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
list_node_s_type* list_get_tail_node(list_head_s_type* list_head);

/***********************************************************************
 * 函数名称: list_destory
 * 功能描述: 链表销毁
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/21
 * 作    者: axk
 ***********************************************************************/
int list_destory(list_head_s_type* list_head);

/***********************************************************************
 * 函数名称: list_init
 * 功能描述: 链表初始化
 * 输    入:list_head 链表头
 * 输    出: 无
 * 返 回 值: 成功返回0 失败返回对应错误码
 * 其    他:
 * 日    期: 2022/11/22
 * 作    者: axk
 ***********************************************************************/
int list_init(list_head_s_type* list_head);
/****************************LINK_LIST 函数声明 end****************************************************/
#ifdef __cplusplus
}
#endif
#endif

链表接口测试代码

/*********************************************************************
 * 版权所有 (c) 2021-2022  axk. 保留所有版权
 * 文件名称: linklist_test.c
 * 文件描述: 链表接口测试文件
 * 作    者: axk
 * 创建日期: 2022/11/21
 * 作    者                 日    期                 版    本          修改摘要
 * axk                   2022/11/21               1.0           文件创建
**********************************************************************/


/* 示例代码数据内容是char*类型字符串 实际使用可以是任意类型指针 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "linklist.h"
#include "axk_base_data_type.h"

void print_list(list_head_s_type* list_head)
{
    
    
    list_node_s_type* tmp_node = NULL;
    int i = 0;
    if (NULL == list_head || 0 == list_head->node_num)
    {
    
    
        printf("curr list is NULL!\n");
        return ;
    }

    tmp_node = list_head->head;
    while (NULL != tmp_node)
    {
    
    
        printf("node %d content %s.\n", i++, (char*)tmp_node->data);
        tmp_node = tmp_node->next;
    }
}

int main(void)
{
    
    
    int menu = 0;
    list_head_s_type list_head;
    memset(&list_head, 0x0, sizeof(list_head_s_type));

    list_init(&list_head);

    while (1)
    {
    
    
        print_list(&list_head);
        menu = 0;
        printf("please select menu: \n" \
                "1.head insert \n" \
                "2.tail insert\n" \
                "3.head delete\n" \
                "4.tail delete\n" \
                "5.delete by data address\n" \
                "6.head get\n" \
                "7.tail get\n" \
                "8.destory list\n" \
                "9.init list\n" \
                "0.exit \n");

        scanf("%d", &menu);

        switch (menu)
        {
    
    
            case 1:
            {
    
    
                char* data = (char*)malloc(128);
                if (NULL == data)
                {
    
    
                    printf("\nmalloc failed!\n");
                    break;
                }
                memset(data, 0x0, 128);
                printf("please input data:\n");
                scanf("%s", data);
                list_head_insert(&list_head, data, free);
                break;
            }
            case 2:
            {
    
    
                char* data = (char*)malloc(128);
                if (NULL == data)
                {
    
    
                    printf("\nmalloc failed!\n");
                    break;
                }
                memset(data, 0x0, 128);
                printf("please input data:\n");
                scanf("%s", data);
                list_tail_insert(&list_head, data, free);
                break;
            }
            case 3:
            {
    
    
                list_head_del(&list_head);
                break;
            }
            case 4:
            {
    
    
                list_tail_del(&list_head);
                break;
            }
            case 5:
            {
    
    
                /* 当前示例是获取尾部节点然后删除 */
                list_node_s_type* tmp_node = list_get_tail_node(&list_head);
                if (NULL != tmp_node)
                {
    
    
                    list_del_node_by_data_addrress(&list_head, tmp_node->data);
                }
                else
                {
    
    
                    printf("list is NULL!\n");
                }
                break;
            }
            case 6:
            {
    
    
                list_node_s_type* tmp_node = list_get_head_node(&list_head);
                if (NULL != tmp_node)
                {
    
    
                    printf("node data is %s\n", (char*)tmp_node->data);
                }
                else
                {
    
    
                    printf("list is NULL!\n");
                }
                break;
            }
            case 7:
            {
    
    
                list_node_s_type* tmp_node = list_get_tail_node(&list_head);
                if (NULL != tmp_node)
                {
    
    
                    printf("node data is %s\n", (char*)tmp_node->data);
                }
                else
                {
    
    
                    printf("list is NULL!\n");
                }
                break;
            }
            case 8:
            {
    
    
                list_destory(&list_head);
                break;
            }
            case 9:
            {
    
    
                list_init(&list_head);
                break;
            }
            case 0:
            {
    
    
                exit(0);
                break;
            }

            default:
            {
    
    
                printf("nosuppurt menu %d!!!\n", menu);
                break;
            }
        }
    }

    list_destory(&list_head);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38721267/article/details/128116447