今天無聊用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