沉淀之log4c的list
log4c中对于链表也实现了一套,可以在src/sd/目录下找到有对应的list.c和list.h两个文件。直接贴代码和注释。
![]()
list.h
#ifndef __sd_list_h#define __sd_list_h#include <stddef.h>#include "defs.h"__SD_BEGIN_DECLS/*** 声明list类型,实际定义是在list.c文件里*/typedef struct __sd_list sd_list_t;/*** 定义list中元素的结构,data应该是指向用户数据的指针,* 双向链表*/struct __sd_list_iter {void* data;struct __sd_list* list;struct __sd_list_iter* __next;struct __sd_list_iter* __prev;int __foreach;};/*** 对于元素容器进行类型的定义*/typedef struct __sd_list_iter sd_list_iter_t;/*** foreach遍历时的回调函数类型*/typedef unsigned int (*sd_list_func_t)(void* a_data, void* a_userdata);/*** 新建一个链表* @param a_capacity 初始化链表中容纳元素的数量* @return 链表的入口指针.*/extern sd_list_t* sd_list_new(size_t a_capacity);/*** 销毁一个链表* @todo 需要一个回调函数来释放用户数据(尚未实现)*/extern void sd_list_delete(sd_list_t* a_this);/*** 将用户数据插入到链表的头部*/extern sd_list_iter_t* sd_list_prepend(sd_list_t* a_this, void* a_data);/*** 将用户数据插入到链表的尾部*/extern sd_list_iter_t* sd_list_append(sd_list_t* a_this, void* a_data);/*** 在链表里查找用户数据是否存在* @param a_data 待查找数据* @return 找到的元素地址,或者NULL.*/extern sd_list_iter_t* sd_list_lookup(sd_list_t* a_this, void* a_data);/*** 在链表里查找数据,如果没有找到就调用sd_list_add().将数据插入到链表里* @param a_data 待查找数据* @return 查找到的数据地址,或者NULL.*/extern sd_list_iter_t* sd_list_lookadd(sd_list_t* a_this, void* a_data);/*** 将用户数据插入到链表里,如果该数据已经存在则返回数据的指针* @warning 元素会插入到链表的头部* @param a_data 带插入数据* @return 返回插入的或者已存在的元素指针*/extern sd_list_iter_t* sd_list_add(sd_list_t* a_this, void* a_data);/*** 用a_func从头遍历链表中的所有元素,直到返回一个非NULL的返回值,则* 将用户数据插入到返回的数据前面* @param a_func 排序函数* @param a_data 待插入的用户数据* @return 用户数据插入后所在的容器指针*/extern sd_list_iter_t* sd_list_sortadd(sd_list_t* a_this,sd_list_func_t a_func,void* a_data);/*** 从链表里删除一个用户数据* @param a_data 包含用户数据的容器地址*/extern int sd_list_del(sd_list_t* a_this, void* a_data);/*** 清空一个链表*/extern void sd_list_clear(sd_list_t* a_this);/*** 调用a_func从头遍历整个链表直到返回一个非0* @param a_func 遍历回调函数* @param a_data 传入到回调函数的一个用户数据*/extern void sd_list_foreach(sd_list_t* a_this, sd_list_func_t a_func,void* a_userdata);/*** 调用a_func从后向前遍历整个链表直到返回一个非0* @param a_func 遍历回调函数* @param a_data 传入到回调函数的用户数据*/extern void sd_list_rforeach(sd_list_t* a_this, sd_list_func_t a_func,void* a_userdata);/*** 获取链表中元素的个数*/extern size_t sd_list_get_nelem(sd_list_t* a_this);/*** 获取链表中第一个容器*/extern sd_list_iter_t* sd_list_begin(sd_list_t* a_this);/*** Gets the past-the-last-element iterator of the list.* 函数定义未实现*/extern sd_list_iter_t* sd_list_end(sd_list_t* a_this);/*** 获取链表中最后一个元素*/extern sd_list_iter_t* sd_list_rbegin(sd_list_t* a_this);/*** Gets the before-the-first-element iterator of the list.* 函数定义未实现*/extern sd_list_iter_t* sd_list_rend(sd_list_t* a_this);/*** 得到当前容器的下一个容器*/extern sd_list_iter_t* sd_list_iter_next(sd_list_iter_t* a_this);/*** 得到当前容器的前一个容器*/extern sd_list_iter_t* sd_list_iter_prev(sd_list_iter_t* a_this);/*** 从链表中删除一个容器*/extern void sd_list_iter_del(sd_list_iter_t* a_this);/*** 创建一个新的容器并将数据插入到a_this前面* @param a_data 放入到新建容器的数据*/extern sd_list_iter_t* sd_list_iter_insert(sd_list_iter_t* a_this,void* a_data);__SD_END_DECLS#endif
list.h中声明的函数,是在list.c中进行了实现,其中声明的两个函数:
extern sd_list_iter_t* sd_list_end(sd_list_t* a_this);
extern sd_list_iter_t* sd_list_rend(sd_list_t* a_this);
功能与
extern sd_list_iter_t* sd_list_begin(sd_list_t* a_this);
extern sd_list_iter_t* sd_list_rbegin(sd_list_t* a_this);
重复,所以在list.c里面只进行定义了一个空的函数体,并没有进行实现。
以下是list.c中的内容:
#include "list.h"#include "malloc.h"#include <stdlib.h>struct __sd_list {sd_list_iter_t* head;sd_list_iter_t* tail;size_t nelem;};
list.h中有一个typedef语句:typedef struct __sd_list sd_list_t; 将sd_list_t声明一下然后在这里进行实际的结构体的定义,这样下面的函数声明中就可以使用这个sd_list_t进行参数或者返回值的声明了。并且只要引用了list.h就可以使用sd_list_t来进行定义自己的链表句柄。这样可以比较完美的实现结构体的隐藏同时还能比较容易使用。
从这里就知道了整个链表的结构是什么样的了。具体的可以参考图一:

图一:链表的整体结构图
sd_list_new:
extern sd_list_t* sd_list_new(size_t a_capacity){sd_list_t* this;//申请内存,并初始化。实际上calloc分配的就是初始化了的内存。this = sd_calloc(1, sizeof(sd_list_t));this->head = 0;this->tail = 0;this->nelem = 0;return this;}
sd_list_prepend:
extern sd_list_iter_t* sd_list_prepend(sd_list_t* a_this, void* a_data){//定义一个容器,参数有效性判断。并进行容器内存分配和检查sd_list_iter_t* i;if (! a_this) return 0;if ((i = sd_calloc(1, sizeof(*i))) == 0)return 0;//填充容器,用户数据,链表等。i->list = a_this;i->data = a_data;i->__prev = 0;i->__next = a_this->head;a_this->head = i;//接通后面的链表,否则设置链表的tail指针的指向if (i->__next)i->__next->__prev = i;elsea_this->tail = i;//增加元素计数器a_this->nelem++;return i;}
sd_list_append:
extern sd_list_iter_t* sd_list_append(sd_list_t* a_this, void* a_data){sd_list_iter_t* i;if (! a_this) return 0;//定义一个容器,参数有效性判断。并进行容器内存分配和检查if ((i = sd_calloc(1, sizeof(*i))) == 0)return 0;//填充容器,用户数据,链表等。i->list = a_this;i->data = a_data;i->__prev = a_this->tail;i->__next = 0;a_this->tail = i;//链接前面的链表或者设置链表的head指针if (i->__prev)i->__prev->__next = i;elsea_this->head = i;//计数器加一a_this->nelem++;return i;}
sd_list_delete:
extern void sd_list_delete(sd_list_t* a_this){sd_list_iter_t *a_next;sd_list_iter_t *a_current;if (!a_this)return;//释放所有的容器/* Free the iterators */if (a_this->nelem > 0){a_current = a_this->head;do {a_next = a_current->__next;free(a_current);a_current = a_next;} while (a_current);}//释放链表 句柄free(a_this);}
sd_list_clear:
extern void sd_list_clear(sd_list_t* a_this){a_this->head = 0;a_this->tail = 0;a_this->nelem = 0;}
sd_list_get_nelem:
extern size_t sd_list_get_nelem(sd_list_t* a_this){return (a_this ? a_this->nelem : 0);}
sd_list_begin:
extern sd_list_iter_t* sd_list_begin(sd_list_t* a_this){return (a_this ? a_this->head : 0);}
sd_list_rbegin:
extern sd_list_iter_t* sd_list_rbegin(sd_list_t* a_this){return (a_this ? a_this->tail : 0);}
sd_list_lookup:
extern sd_list_iter_t* sd_list_lookup(sd_list_t* a_this, void* a_data){sd_list_iter_t* i;if (! a_this) return 0;//遍历直到找到数据地址与用户传入的地址相同,返回容器地址for (i = a_this->head; i; i = i->__next)if (a_data == i->data)return i;return 0;}
sd_list_add:
extern sd_list_iter_t* sd_list_add(sd_list_t* a_this, void* a_data){sd_list_iter_t* i;if (! a_this) return 0;//新建一个容器并分配内存检查if ((i = sd_calloc(1, sizeof(*i))) == 0)return 0;//填充i->data = a_data;i->list = a_this;i->__next = a_this->head;i->__prev = 0;a_this->head = i;//插入首部if (i->__next) i->__next->__prev = i;if (!a_this->tail) a_this->tail = i;//计数器加一a_this->nelem++;return i;}
sd_list_lookadd:
extern sd_list_iter_t* sd_list_lookadd(sd_list_t* a_this, void* a_data){sd_list_iter_t* i;if (! a_this) return 0;//调用sd_list_lookup,或者就插入并返回if ((i = sd_list_lookup(a_this, a_data)) != 0)return i;return sd_list_add(a_this, a_data);}
sd_list_iter_insert:
extern sd_list_iter_t* sd_list_iter_insert(sd_list_iter_t* a_this,void* a_data){sd_list_iter_t* i;if (! a_this) return 0;//如果錫_this就是头节点那么就头插if (a_this->list->head == a_this)return sd_list_prepend(a_this->list, a_data);//申请内存,填充后插入到a_this之前if ((i = sd_calloc(1, sizeof(*i))) == 0)return 0;i->data = a_data;i->list = a_this->list;i->__prev = a_this->__prev;i->__next = a_this;/* CAUTION: always exists since a_this is not the head */a_this->__prev->__next = i;a_this->__prev = i;//计数器加一a_this->list->nelem++;return i;}
sd_list_sortadd:
extern sd_list_iter_t* sd_list_sortadd(sd_list_t* a_this,sd_list_func_t a_func, void* a_data){sd_list_iter_t* i;//参数检查if (! a_this || ! a_func) return 0;//从头遍历直到找到一个大于当前用户数据的位置for (i = a_this->head; i; i = i->__next)if ((*a_func)(i->data, a_data) > 0)break;//如果不是最后的位置,那么插入新节点到a_data之前。否则添加在最后if (i)return sd_list_iter_insert(i, a_data);elsereturn sd_list_append(a_this, a_data);}
sd_list_iter_del:
extern void sd_list_iter_del(sd_list_iter_t* a_this){if (!a_this)return;if (a_this->__foreach == 1) {a_this->__foreach = 0;return;}//向后接通if (a_this->__next)a_this->__next->__prev = a_this->__prev;elsea_this->list->tail = a_this->__prev;//向前接通if (a_this->__prev)a_this->__prev->__next = a_this->__next;elsea_this->list->head = a_this->__next;//计数器减一a_this->list->nelem--;//释放当前数据free(a_this);}
sd_list_del:
extern int sd_list_del(sd_list_t* a_this, void* a_data){sd_list_iter_t* i;if (!a_this)return -1;//遍历直到找到这个数据for (i = a_this->head; i; i = i->__next)if (a_data == i->data)break;//如果没找到if (!i)return -1;//删除这个元素sd_list_iter_del(i);return 0;}
sd_list_foreach:
extern void sd_list_foreach(sd_list_t* a_this, sd_list_func_t a_func,void* a_userdata){sd_list_iter_t* i;sd_list_iter_t* j;if (!a_this || !a_func)return;//从头到尾遍历整个链表for (i = a_this->head; i; i = j){int ret;i->__foreach = 1;ret = (*a_func)(i->data, a_userdata);j = i->__next;if (i->__foreach == 0)sd_list_iter_del(i);elsei->__foreach = 0;if (ret) return;}}
sd_list_rforeach:
extern void sd_list_rforeach(sd_list_t* a_this, sd_list_func_t a_func,void* a_userdata){sd_list_iter_t* i;sd_list_iter_t* j;if (!a_this || !a_func)return;for (i = a_this->tail; i; i = j) {int ret;i->__foreach = 1;ret = (*a_func)(i->data, a_userdata);j = i->__prev;if (i->__foreach == 0)sd_list_iter_del(i);elsei->__foreach = 0;if (ret) return;}}
sd_list_iter_next:
extern sd_list_iter_t* sd_list_iter_next(sd_list_iter_t* a_this){return (a_this ? a_this->__next : 0);}
sd_list_iter_prev:
extern sd_list_iter_t* sd_list_iter_prev(sd_list_iter_t* a_this){return (a_this ? a_this->__prev : 0);}
一个简单的样例测试程序如下:
main.c
#include <stdio.h>#include <stdlib.h>#include "stack.h"#include "list.h"typedef struct test{int a;int b;int c;}test_t;static unsigned int print(void *data, void *p){test_t *t = (test_t *)data;printf("a:%d b:%d c:%d\n",t->a, t->b, t->c);return 0;}int main(){sd_list_t* a_this = sd_list_new(24);test_t *t3 = malloc(sizeof(test_t));t3->a = 3;t3->b = 4;t3->c = 5;sd_list_prepend(a_this, t3);test_t *t1 = malloc(sizeof(test_t));t1->a = 1;t1->b = 2;t1->c = 3;sd_list_prepend(a_this, t1);test_t *t2 = malloc(sizeof(test_t));t2->a = 2;t2->b = 3;t2->c = 4;sd_list_prepend(a_this, t2);sd_list_foreach(a_this, print, NULL);printf("remains in list:%d\n", sd_list_get_nelem(a_this));sd_list_delete(a_this);return 0;}
浙公网安备 33010602011771号