C语言中能否为链表实现泛型函数?无需为不同结构体编写专属操作函数
在C中实现泛型链表操作的实用技巧
当然不用为每个结构体单独写链表操作函数啦!C虽然不像C++那样有原生泛型,但咱们有好几种办法实现通用的链表工具,完全不用重复造轮子~
方法1:用void*打造通用操作函数
C里所有指针本质都是内存地址,void*可以接受任意类型的指针。结合你给出的两个结构体——它们都把next指针放在成员的第一个位置,这刚好可以简化操作:
// 通用的添加节点函数 void add_node(void **head, void *new_node) { // 因为结构体的第一个成员是next指针,所以直接把new_node转成void**就能拿到next的地址 void **node_next = (void**)new_node; *node_next = *head; // 新节点的next指向原表头 *head = new_node; // 更新表头为新节点 }
使用的时候只需要把结构体指针的地址转成void**就行:
// 操作first_struct链表 struct first_struct *first_head = NULL; struct first_struct *new_first = malloc(sizeof(struct first_struct)); new_first->a = 10; new_first->b = 20; add_node((void**)&first_head, new_first); // 操作second_struct链表 struct second_struct *second_head = NULL; struct second_struct *new_second = malloc(sizeof(struct second_struct)); new_second->a = 100; new_second->b = 200; new_second->c = 300; add_node((void**)&second_head, new_second);
如果你的结构体里next不是第一个成员也没关系,用offsetof(需要包含<stddef.h>)计算偏移量就行:
#include <stddef.h> void add_node(void **head, void *new_node, size_t next_offset) { // 计算next指针的地址 void **node_next = (void*)((char*)new_node + next_offset); *node_next = *head; *head = new_node; } // 使用时传入next的偏移量 add_node((void**)&first_head, new_first, offsetof(struct first_struct, next));
方法2:用宏自动生成类型安全的专属函数
如果你觉得void*的类型不够安全,怕不小心传错指针,可以用宏来自动生成针对每个结构体的操作函数,既不用重复写代码,又能保留类型检查:
// 定义生成add_node函数的宏 #define DEFINE_ADD_NODE_FUNC(struct_type) \ void add_##struct_type##_node(struct_type **head, struct_type *new_node) { \ new_node->next = *head; \ *head = new_node; \ } // 为两个结构体生成专属函数 DEFINE_ADD_NODE_FUNC(first_struct); DEFINE_ADD_NODE_FUNC(second_struct);
这样预编译后会自动生成add_first_struct_node和add_second_struct_node两个函数,使用的时候直接调用就行,完全不用手写重复代码:
add_first_struct_node(&first_head, new_first); add_second_struct_node(&second_head, new_second);
总结
两种方法各有优劣:
void*方案更灵活,一个函数通吃所有链表结构体,但牺牲了一点类型安全;- 宏方案保留了类型检查,调用起来更直观,而且完全不用重复编写函数逻辑。
你可以根据自己的需求选合适的方式,没必要为每个结构体单独写一遍操作函数~
内容的提问来源于stack exchange,提问作者abt jeremie
相关产品推荐
相关产品推荐

