一个好的C等价的STL载体?

我注意到在我们的代码库中的几个地方,我们使用动态扩展数组,即一个与元素计数器和“max elements”值相结合的基本数组。

我想要做的是用通常的数据结构和实用程序函数替换它们,这是出于通常的面向对象的原因。 数组元素可以是基本数据类型或结构,我需要快速随机访问元素,最好是类型安全的实现。

所以,基本上,我想要使用的是STL向量,但代码库仅限于C89,所以我必须提出其他的东西:-)

我给了它一些想法并掀起了这个初稿,只是为了表明我的目标:

/* Type-safe dynamic list in C89 */ #define list_declare(type) typedef struct _##type##_list_t { type * base_array; size_t elements; size_t max_size; } type##_list_t #define list(type) type##_list_t #define list_new(type, initial_size) { calloc(initial_size, sizeof(type)), 0, initial_size } #define list_free(list) free(list.base_array) #define list_set(list, place, element) if ( list.elements < list.max_size ) { list.base_array[place] = element; } else { /* Array index out of bounds */ } #define list_add(list, element) if ( list.elements < list.max_size ) { list.base_array[list.elements++] = element; } else { /* Expand array then add */ } #define list_get(list, n) list.base_array[n] /* Sample usage: */ list_declare(int); int main(void) { list(int) integers = list_new(int, 10); printf("list[0] = %d\n", list_get(integers, 0)); list_add(integers, 4); printf("list[0] = %d\n", list_get(integers, 0)); list_set(integers, 0, 3); printf("list[0] = %d\n", list_get(integers, 0)); list_free(integers); return EXIT_SUCCESS; } 

……但是,必须有其他人以前做过这件事。 我知道FreeBSD sys / queue.h对一些不同队列的类似概念的实现,但我找不到类似于数组的东西。

这里有人更聪明吗?

glib提供了一种GArray类型,它实现了一个动态增长的数组。 如果你可以使用外部的第三方库,glib几乎总是作为C的“标准”库的一个很好的选择。它为所有基本数据结构,unicode字符串,日期和时间值等提供类型。

有sglib,它以通用方式实现各种列表,哈希映射和rbtree(即通过专门化类型)。 数组还有一个快速排序function:

qLibc在纯C中实现了一个向量。数据结构允许它存储任何类型的对象,如(void * object),它为字符串,格式化字符串和整数类型提供了方便的包装。

这是您的想法的示例代码。

 qvector_t *vector = qvector(QVECTOR_OPT_THREADSAFE); vector->addstr(vector, "Hello"); vector->addstrf(vector, "World %d", 123); char *finalstring = vector->tostring(vector); printf("%s", finalstring); free(finalstring) vector->free(vector); 

对象类型:

 int a = 1, b = 2; qvector_t *vector = qvector(QVECTOR_OPT_THREADSAFE); vector->add(vector, (void *)&a, sizeof(int)); vector->add(vector, (void *)&b, sizeof(int)); int *finalarray = vector->toarray(vector); printf("a = %d, b = %d", finalarray[0], finalarray[1]); free(finalarray) vector->free(vector); 

注意)我制作了这个示例代码仅供您参考,从示例代码中复制。 它可能有拼写错误。

您可以访问http://wolkykim.github.io/qlibc/查看完整的API参考资料。

这里有一个简单的矢量替换,它的所有function,它严格的C89和线程安全; 库对我来说太难了,我用自己的; 没有性能,但易于使用

 /* owner-structs too */ typedef struct { char name[20],city[20]; int salary; } My,*Myp; typedef char Str80[80]; /* add here your type with its size */ typedef enum {SPTR,INT=sizeof(int),DOUBLE=sizeof(double),S80=sizeof(Str80),MY=sizeof(My)} TSizes; typedef enum {ADD,LOOP,COUNT,FREE,GETAT,GET,REMOVEAT,REMOVE} Ops; void *dynarray(char ***root,TSizes ts,Ops op,void *in,void *out) { size_t d=0,s=in?ts?ts:strlen((char*)in)+1:0; char **r=*root; while( r && *r++ ) ++d; switch(op) { case ADD: if( !*root ) *root=calloc(1,sizeof r); *root=realloc(*root,(d+2)*sizeof r); memmove((*root)+1,*root,(d+1)*sizeof r); memcpy(**root=malloc(s),in,s); break; case LOOP: while( d-- ) ((void (*)(char*))in)((*root)[d]); break; case COUNT: return *(int*)out=d,out; case FREE: if(r) { ++d; while( d-- ) realloc((*root)[d],0); free(*root);*root=0; } break; case GETAT: { size_t i=*(size_t*)in; if(r && i<=--d) return (*root)[di]; } break; case GET: { int i=-1; while( ++i,d-- ) if( !(ts?memcmp:strncmp)(in,(*root)[d],s) ) return *(int*)out=i,out; return *(int*)out=-1,out; } case REMOVEAT: { size_t i=*(size_t*)in; if(r && i<=--d) { free((*root)[di]); memmove(&(*root)[di],&(*root)[d-i+1],(d-i+1)*sizeof r); return in; } } break; case REMOVE: while( *(int*)dynarray(root,ts,GET,in,&d)>=0 ) dynarray(root,ts,REMOVEAT,&d,0); } return 0; } void outmy(Myp s) { printf("\n%s,%s,%d",s->name,s->city,s->salary); } main() { My z[]={{"Buffet","Omaha",INT_MAX},{"Jobs","Palo Alto",1},{"Madoff","NYC",INT_MIN}}; Str80 y[]={ "123","456","7890" }; char **ptr=0; int x=1; /* precondition for first use: ptr==NULL */ dynarray(&ptr,SPTR,ADD,"test1.txt",0); dynarray(&ptr,SPTR,ADD,"test2.txt",0); dynarray(&ptr,SPTR,ADD,"t3.txt",0); dynarray(&ptr,SPTR,REMOVEAT,&x,0); /* remove at index/key ==1 */ dynarray(&ptr,SPTR,REMOVE,"test1.txt",0); dynarray(&ptr,SPTR,GET,"t3.txt",&x); dynarray(&ptr,SPTR,LOOP,puts,0); /* another option for enumerating */ dynarray(&ptr,SPTR,COUNT,0,&x); while( x-- ) puts(ptr[x]); dynarray(&ptr,SPTR,FREE,0,0); /* frees all mallocs and set ptr to NULL */ /* start for another (user)type */ dynarray(&ptr,S80,ADD,y[0],0); dynarray(&ptr,S80,ADD,y[1],0); dynarray(&ptr,S80,ADD,y[2],0); dynarray(&ptr,S80,ADD,y[0],0); dynarray(&ptr,S80,LOOP,puts,0); dynarray(&ptr,S80,FREE,0,0); /* frees all mallocs and set ptr to NULL */ /* start for another (user)struct-type */ dynarray(&ptr,MY,ADD,&z[0],0); dynarray(&ptr,MY,ADD,&z[1],0); dynarray(&ptr,MY,ADD,&z[2],0); dynarray(&ptr,MY,ADD,&z[0],0); dynarray(&ptr,MY,LOOP,outmy,0); dynarray(&ptr,MY,FREE,0,0); return 0; } 

我通常会为了这样的目的滚动我自己的代码,就像你一样。 这并不是特别困难,但如果没有整个OO框架,则不容易实现类型安全等。

如前所述,glib提供了你所需要的 – 如果glib2对你来说太大了,你仍然可以使用glib1.2。 它已经很老了,但没有外部依赖(如果你需要线程支持,除了pthread)。 如有必要,代码也可以集成到更大的项目中。 它是LGPL许可的。

到目前为止,我正在使用以下宏实现而没有问题。 它不是一个完整的实现,而是自动增长数组:

 #define DECLARE_DYN_ARRAY(T) \ typedef struct \ { \ T *buf; \ size_t n; \ size_t reserved; \ } T ## Array; #define DYN_ARRAY(T) T ## Array #define DYN_ADD(array, value, errorLabel) DYN_ADD_REALLOC(array, value, errorLabel, realloc) #define DYN_ADD_REALLOC(array, value, errorLabel, realloc) \ { \ if ((array).n >= (array).reserved) \ { \ if (!(array).reserved) (array).reserved = 10; \ (array).reserved *= 2; \ void *ptr = realloc((array).buf, sizeof(*(array).buf)*(array).reserved); \ if (!ptr) goto errorLabel; \ (array).buf = ptr; \ } \ (array).buf[(array).n++] = value; \ } 

首先使用你写的: DECLARE_DYN_ARRAY(YourType)

要声明变量,请编写DYN_ARRAY(YourType) array = {0}

使用DYN_ADD(array, element, errorLabel)添加元素。

您可以使用array.buf[i]访问元素。

你可以通过array.n获得元素的数量。

完成后,您可以使用free(array.buf) (或者您用于分配它的任何函数free(array.buf)它。