You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言链表与树库泛化数据类型实现方案问询

这是C语言里实现泛型数据结构的经典场景,我给你一套实用的解决方案,核心就是用void*来承载任意类型数据,再配合类型专属的操作函数,让同一个链表库搞定所有数据类型的需求。

泛型链表实现方案

1. 重新设计链表结构

首先修改头文件,把固定的list_element换成void*,同时给链表绑定一个操作函数集——用来处理不同类型的复制、销毁(甚至比较)逻辑,这是实现泛型的关键:

/* list.h */
#ifndef LIST_H
#define LIST_H

#include <stdlib.h>

// 定义操作函数集,每种数据类型对应一套专属实现
typedef struct list_ops {
    // 复制元素:输入原数据指针,返回复制后的新数据指针
    void* (*copy)(const void* data);
    // 销毁元素:释放元素占用的内存
    void (*destroy)(void* data);
    // 可选:元素比较函数,用于排序、查找等场景
    int (*compare)(const void* a, const void* b);
} list_ops;

struct list_node {
    void* value;  // 用void*存储任意类型数据
    struct list_node* next;
};
typedef struct list_node list_node;

// 链表结构体,绑定对应的操作函数集
typedef struct {
    list_node* head;
    const list_ops* ops;
} list;

// 创建空链表,传入该链表对应的操作函数集
list list_create(const list_ops* ops);

// 向链表头部添加元素
list list_cons(list l, const void* data);

// 销毁整个链表(包括所有元素)
void list_destroy(list l);

#endif // LIST_H

2. 实现链表核心逻辑

在list.c里,我们只需要调用操作函数集里的方法,完全不需要关心具体的数据类型是什么:

/* list.c */
#include "list.h"

list list_create(const list_ops* ops) {
    list new_list = { .head = NULL, .ops = ops };
    return new_list;
}

list list_cons(list l, const void* data) {
    list_node* new_node = malloc(sizeof(list_node));
    if (!new_node) {
        // 内存分配失败,可根据需求添加错误处理逻辑
        return l;
    }
    // 调用类型专属的copy函数复制数据(深拷贝)
    new_node->value = l.ops->copy(data);
    new_node->next = l.head;
    l.head = new_node;
    return l;
}

void list_destroy(list l) {
    list_node* current = l.head;
    while (current != NULL) {
        list_node* next = current->next;
        // 调用类型专属的destroy函数释放元素
        l.ops->destroy(current->value);
        free(current);
        current = next;
    }
    l.head = NULL;
}

3. 为不同类型实现操作函数

现在你可以为int、double或者自定义结构体,分别实现对应的操作函数,完全不需要修改链表库本身:

示例1:int类型链表的操作函数

// 复制int类型数据
void* int_copy(const void* data) {
    int* copy = malloc(sizeof(int));
    *copy = *(const int*)data;
    return copy;
}

// 销毁int类型数据
void int_destroy(void* data) {
    free(data);
}

// 比较两个int值
int int_compare(const void* a, const void* b) {
    const int* ia = (const int*)a;
    const int* ib = (const int*)b;
    return *ia - *ib;
}

// int类型的操作函数集实例
const list_ops int_list_ops = {
    .copy = int_copy,
    .destroy = int_destroy,
    .compare = int_compare
};

示例2:自定义结构体的操作函数

typedef struct {
    char name[20];
    int age;
} Person;

// 复制Person结构体(如果结构体里有指针成员,这里要做深拷贝)
void* person_copy(const void* data) {
    Person* copy = malloc(sizeof(Person));
    *copy = *(const Person*)data;
    return copy;
}

// 销毁Person数据
void person_destroy(void* data) {
    free(data);
}

// 按年龄比较Person
int person_compare(const void* a, const void* b) {
    const Person* pa = (const Person*)a;
    const Person* pb = (const Person*)b;
    return pa->age - pb->age;
}

// Person类型的操作函数集实例
const list_ops person_list_ops = {
    .copy = person_copy,
    .destroy = person_destroy,
    .compare = person_compare
};

4. 在main中使用泛型链表

这样你就能在同一个程序里同时使用不同类型的链表了,完全不需要多套链表代码:

/* main.c */
#include "list.h"
#include <stdio.h>

// 这里引入上面定义的int和Person的操作函数

int main() {
    // 创建int类型链表
    list int_list = list_create(&int_list_ops);
    int a = 10, b = 20, c = 30;
    int_list = list_cons(int_list, &a);
    int_list = list_cons(int_list, &b);
    int_list = list_cons(int_list, &c);

    // 遍历int链表
    list_node* current = int_list.head;
    printf("Int list: ");
    while (current) {
        printf("%d ", *(int*)current->value);
        current = current->next;
    }
    printf("\n");

    // 创建Person类型链表
    list person_list = list_create(&person_list_ops);
    Person p1 = { "Alice", 25 }, p2 = { "Bob", 30 };
    person_list = list_cons(person_list, &p1);
    person_list = list_cons(person_list, &p2);

    // 遍历Person链表
    current = person_list.head;
    printf("Person list: ");
    while (current) {
        Person* p = (Person*)current->value;
        printf("%s(%d) ", p->name, p->age);
        current = current->next;
    }
    printf("\n");

    // 销毁链表,避免内存泄漏
    list_destroy(int_list);
    list_destroy(person_list);

    return 0;
}

核心思路总结

  • 用void*作为通用数据容器,让链表可以存储任意类型的数据;
  • 通过操作函数集把类型相关的逻辑(复制、销毁、比较)和链表核心逻辑分离,每种类型只需要实现自己的操作函数即可;
  • 这种方式真正实现了泛型,同一个链表库适配所有基本类型和自定义结构体,彻底解决了重复编写多套链表代码的问题。

内容的提问来源于stack exchange,提问作者LucaLumetti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:13:57