今天无聊用C语言写了一个容器list,我发现现在微软的vs2010已经很规范的处理C语言的编译工作了。比如说变量声明必须在函数最前面,声明一个struct变量的时候必须加上struct关键字等等。
扩展性:为了让这个list支持任意类型,list中的节点存储两个变量:一个是用户自定义的类型的对象的地址,一个是next指针。一开始我想把操作都封装起来,全部声明为静态的,然后在operations结构体中放入指向这些静态函数的指针。但是后来一想这样其实也没多大必要,因为我必须定义一个形参,这个形参为当前的list。所以干脆就把这些操作暴露给用户。
与其写出
list animals
animals.oprs.insert(&animals,&eliphant);这样的代码
还不如写出
list animals
listinsert(&animals,&eliphant);
内存管理:其实内存管理是一项非常有意思的工作,但是这里我只是简单的处理了一下,没有实现什么内存池啥的。对于内存管理当然要遵循谁申请谁释放的原则了。node是不能暴露给用户的。
遍历操作:遍历操作需要用户自己写一个回调函数实现自己想要的那套处理方法。列表的插入删除操作啥的这个仁者见仁智者见智了。我的插入操作时在链表头插入。
下面是头文件
#ifndef LIST_H #define LIST_H #include <stdio.h> #include <malloc.h> #ifdef __cplusplus extern "C"{ #endif struct list; struct node; struct operations;/*废弃*/ typedef struct node{ unsigned int value; struct node* next; }node,*nodeptr; typedef struct operations{ void (*insert)(struct list *l , void* p); void (*remove)(struct list *l , void* p); void (*traverse)(struct list *l , void (*callback)(void*)); }operations,*operaptr; typedef struct list{ nodeptr head; int length; }list; void listinit(struct list* l); void listinsert(struct list *l , void* p); void listremove(struct list *l , void* p); void listtraverse(struct list *l , void(*callback)(void*)); int listlength(struct list *l); static nodeptr listnewnode(); #ifdef __cplusplus } #endif #endif
源文件
#include "list.h" static operations ops={ listinsert, listremove, listtraverse, }; void listinit(list* l) { (*l).head=NULL; (*l).length=0; } void listinsert(list *l , void *thisnode) { nodeptr p=listnewnode(); p->value=(unsigned int)thisnode; p->next=(*l).head; (*l).head=p; (*l).length+=1; } void listremove(list *l , void *thisnode) { nodeptr head; nodeptr prev; prev=(*l).head; if(prev==NULL){ printf("This list is NULL\n"); return ; } if(thisnode==NULL){ printf("this node is NULL\n"); return ; } if(prev->value==(unsigned int)thisnode){ (*l).head=(*l).head->next; free(prev); (*l).length-=1; }else{ for(head=(*l).head ; head!=NULL ; head=head->next){ if((unsigned int)thisnode==head->value){ prev->next=head->next; free(head); (*l).length-=1; break; } prev=head; } if(head==NULL){ printf("This list has no this node\n"); } } } nodeptr listnewnode() { return (nodeptr)malloc(sizeof(node)); } /************************************************************************/ /* if you wanna do something to the node, please write a callback. it */ /* must has the type of void(*callback)(void*) */ /************************************************************************/ void listtraverse(list *l , void(*callback)(void*)) { nodeptr head=(*l).head; for( ; head!=NULL ; head=head->next) callback((void*)(head->value)); } int listlength(list *l) { return (*l).length; }
下面给出一个测试用的代码
#include <stdio.h> #include <stdlib.h> #include "list.h" typedef struct monkey{ int age; int master; int code; }monkey; void callback(void *param) { monkey *thismonkey=(monkey*)param; int sum=thismonkey->age+thismonkey->master+thismonkey->code; printf("%d,%d,%d,SUM:%d\n",thismonkey->age,thismonkey->master,thismonkey->code,sum); } int main(int argc ,char *argv[]) { list animals; monkey jack; monkey rose; monkey tom; monkey *p; listinit(&animals); jack.age=20; jack.master=20; jack.code=20; rose.age=21; rose.master=21; rose.code=21; tom.age=22; tom.master=22; tom.code=22; listinsert(&animals,&jack); listinsert(&animals,&rose); listinsert(&animals,&tom); listtraverse(&animals,callback); listremove(&animals,NULL); listtraverse(&animals,callback); printf("%d\n",listlength(&animals)); system("pause"); return EXIT_SUCCESS; }
如果想使用的话,使用的方法是在包含了list.h头文件后,先要listinit()一下。想要插入的话使用listinsert删除的话用listremove