C语言面向对象的通用链表实现
C语言面向对象的通用链表实现
将接头体看做类似C++中的类,在里面声明数据和方法。其中包括一个链表所必须的数据和操作链表所必须的方法,再定义一个接口用于创建链表。使用指针的原因是防止局部变量被释放掉。
typedef struct node_t Node;
struct node_t
{
void *data;
Node *next;
};
typedef struct
{
void (*user_data_free)(void *data); // 用户释放数据,不包含*data的释放
int (*node_compare)(void *node_data, void *data); // 用户数据和节点数据比较,相等返回0
} clist_user_hooks_t;
typedef struct list_t List;
struct list_t
{
Node *head;
Node *tail;
int size;
clist_user_hooks_t user_hooks;
/* private */
int (*delete_node)(List *plist, Node *pnode);
Node * (*create_node)(List *plist, void *data, size_t size);
/* public */
void (*clist_delete_list)(List *plist);
int (*node_add)(List *plist, void *data, size_t size);
int (*node_del)(List *plist);
int (*node_del_by_data)(List *plist, void *data, int (*p_traverse)(void *node_data, void *data));
void * (*clist_get_data_by_index)(List *plist, int index);
void * (*clist_get_data_by_data)(List *plist, void *data, int (*p_traverse)(void *node_data, void *data));
int (*clist_get_index_by_data)(List *plist, void *data, int (*p_traverse)(void *node_data, void *data));
int (*clist_traverse_list)(List *plist, void *data, int (*p_traverse)(void *node_data, void *data));
};
List * clist_new_list(clist_user_hooks_t *hooks);
实现上面的声明的所有方法。
然后通过函数指针来把这些方法作为List类的方法实现。
例如,实现遍历链表的方法:如下
int clist_traverse_list(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
CLIST_CHECK_PTR_NULL(plist);
Node *pnode = plist->head;
for (; pnode != NULL; pnode = pnode->next)
{
p_traverse(pnode->data, data);
}
return CLIST_OK;
}
在clist_new_list
中进行挂载。
user_hooks
则作为用户钩子来调用用户的接口。因此,需要在创建链表时,传入用户回调,以便在链表操作中使用。
List * clist_new_list(clist_user_hooks_t *user_hooks)
{
if (user_hooks == NULL || user_hooks->user_data_free == NULL || user_hooks->node_compare == NULL)
return NULL;
List *plist = (List *)malloc(sizeof(List));
if (plist == NULL) {
return NULL;
}
plist->head = NULL;
plist->tail = NULL;
plist->size = 0;
plist->user_hooks.user_data_free = user_hooks->user_data_free;
plist->user_hooks.node_compare = user_hooks->node_compare;
plist->create_node = clist_create_node;
plist->delete_node = clist_delete_node;
plist->clist_delete_list = clist_delete_list;
plist->node_add = clist_node_add;
plist->node_del = clist_node_del;
plist->node_del_by_data = clist_node_del_by_data;
plist->clist_get_data_by_data = clist_get_data_by_data;
plist->clist_get_data_by_index = clist_get_data_by_index;
plist->clist_get_index_by_data = clist_get_index_by_data;
plist->clist_traverse_list = clist_traverse_list;
return plist;
}
如果相对链表中的方法和类进行扩充或改写的话,可以使用结构体嵌套来实现继承。
clist_user_hooks_t hooks = {
.user_data_free = free_conf_item,
.node_compare = compare_conf_item};
List *fconf_list = clist_new_list(&hooks);
if (!fconf_list)
{
return 4;
}
NewList *newList;
newList->newList = fconf_list;
newList->clist_sort = fconf_sort;
List *p_newList = (List *)newList;
p_newList->node_add(p_newList, data, sizeof(data));
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!