C泛型__数据结构

来源:互联网 发布:澳门网络博客官方网站 编辑:程序博客网 时间:2024/06/14 18:47
这里通过用C实现一个通用类型的栈结构来加深对数据结构和C指针的一些理解  同时也为一些C通用类型库函数(如排序)的实现提供一些思路
先写一个int 版本的栈用于比较:
typedef struct{     int* elem;     int logicalLen;     int allocLen;}stack;void StackNew(stack* s){     s->logicalLen = 0;     s->allocLen   = 4;     s->elem = (int*)malloc(s->allocLen*sizeof(int));}void StackDestroy(stack* s){     free(s->elem);     s->elem = NULL;}void StackPush(stack* s, int val){     if (s->logicalLen == s->allocLen)     {          s->allocLen *= 2;          s->elem = (int*)realloc(s->elem,s->allocLen*sizeof(int));          assert(s->elem != NULL);     }     s->elem[s->logicalLen] = val;     s->logicalLen++;}void StackPop(stack* s, int* pVal){     assert(s->logicalLen > 0);     s->logicalLen--;     *pVal = s->elem[s->logicalLen];}


这里通过三个变量很简便的表示了栈,当栈满时,通过扩大一倍的策略重新分配空间。为了维持操作的一致性,所有操作都无返回值。
思考一下这里为什么要传栈的地址而不直接传栈

那么接下来我们用操作内存的方式来实现通用性栈结构:
typedef struct{     int logicalLen;     int allocLen;     void* elems;     int elemSize;}stack;void StackNew(stack* s, int size){     s->logicalLen = 0;     s->allocLen = 4;     s->elemSize = size;     s->elems = malloc(s->allocLen*s->elemSize);}void StackDestroy(stack* s){     free (s->elems);     s->elems = NULL;}void StackPush(stack* s, void* pElem){     if(s->logicalLen == s->allocLen)     {          s->allocLen *= 2;          s->elems = realloc(s->elems, s->allocLen*s->elemSize);          assert(s->elems != NULL);     }     void* elemlocal = (char*)s->elems+s->elemSize*s->logicalLen;     memcpy(elemlocal, pElem, s->elemSize);     s->logicalLen++;}void StackPop(stack* s, void*pElem){     assert(s->logicalLen != 0);     void* elemlocal = (char*)s->elems+(s->logicalLen-1)*s->elemSize;     memcpy(pElem, elemlocal, s->elemSize);     s->logicalLen--;}



以上代码能够很好的通过测试 并且运行效率相当快,在C中 我们通过对内存位模式的操作来屏蔽了所有类型及类型长度带来的差异。
现在考虑将以上数据结构变得通用的,更灵活。假如我们要入栈出栈的元素类型是char* 这样将遇到什么问题呢?
如果我们装入的是动态分配的内存,那么我们没有理由确信栈的销毁会在栈为空之后,也就是有可能栈里还有动态分配的内存的指针,栈就被销毁了。导致内存泄漏。
解决的方案是让栈在销毁时释放动态内存空间,而栈怎么知道哪些是栈内存指针哪些是堆内存指针呢?栈不会知道,但是用户知道。因此考虑给栈多加一个用户定义的释放函数用于释放堆空间。

对上一个版本代码做少许改动:
typedef struct{     int logicalLen;     int allocLen;     void* elems;     int elemSize;     void (*freefn)(void*);}stack;void StackNew(stack* s, int size, void (*freefunc)(void*)){     s->logicalLen = 0;     s->allocLen = 4;     s->elemSize = size;     s->elems = malloc(s->allocLen*s->elemSize);     s->freefn = freefunc;}void StackDestroy(stack* s){     if(s->freefn != NULL)          for(int i=0; i<s->logicalLen; i++)          {               s->freefn((char*)s->elems+i*s->elemSize);          }     free (s->elems);     s->elems = NULL;}


当传入普通内置类型时,传入freefn为NULL
当传入类型是字符串时,定义freefn如下:
void freefn(void* p)
//虽然只是一个void指针 但是只要有地址 堆结构自然能知道当初分配了多少字节空间
{
         free(*(char**) p);
}//考虑一下为什么不用free(char* p) 会有什么影响?
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 工作未满一年离职转正定级怎么办 被网络骗贷翻到几十万怎么办 面试通过后迟迟不通知入职怎么办 厂里捡到饭卡花了里面的钱怎么办 上班用自己手机打卡没电怎么办 逸尚考勤机显示超出考勤记录怎么办 下雨穿套裙工装上班好冷怎么办 蚂蚁借呗放款中不到账怎么办 护士电子化注册没有激活码怎么办? 地铁站务员入职体检身高差点怎么办 车子钥匙锁在车里了怎么办 打错账户了怎么办5天了 下岗失业人员在就业后档案怎么办 皮秒祛斑后没有敷面膜怎么办 硕士毕业工资好低不想工作怎么办 车卖了etc忘拿了怎么办 成熟卵泡打破卵针也不破怎么办? 深圳孩子户口挂别人名下上学怎么办 襄阳东风合运花园房贷怎么办下来 猫在外面躲起来找不到了怎么办 本科三批取消以后三本学校怎么办 机票名字多了个字母安检怎么办 出隧道口限速40超速了怎么办 社保交了五年后断交以后该怎么办 躺椅折叠椅坐的地方坏了怎么办 苹果手机锁频密码忘了怎么办 客户要货公司不给进怎么办 高铁23:00买的票怎么办 带电子手刹的车刹车失灵怎么办 下坡刹车失灵遇行人不看车怎么办 跟大车后面看不见红灯闯了怎么办 跟着大货车后面闯了红灯怎么办 如果用工单位不发放加班工资怎么办 事故家属要司机向医院多交钱怎么办 在大学里和室友关系弄僵怎么办 房产证办出来房产局不给证怎么办 单位全员竞聘老员工没岗位怎么办 快件被快递公司签收了没给送怎么办 总公司跑路了分公司代理法人怎么办 大使馆领的结婚证现在离婚怎么办 日本签证照片被使馆贴错了怎么办