C语言库比较少,很大的原因就是没有泛型,也没有class。但是C语言作为一个较为底层的系统级语言,操纵内存还是很灵活的。模仿C++实现一个泛型vector,可以使用void*,使用的时候强转对应类型,或者使用宏来封装一些操作。
这里实现一个极简的vector,拥有增删查功能,存储的元素放在连续内存中,扩容时1.5倍增长。没有加锁,非线程安全。这个可以在控制结构体里添加。原理很简单,内存不够了,malloc一个原来1.5倍容量的新数组,把老的数据memcpy过去然后释放。删除时,memmove对应元素即可。
C没有class,那么就把控制部分定义成一个结构体,在每个函数的收个入参传入,模拟CPP里的隐藏的首参数this指针一样。结构体定义细节也可以不对外部暴露,放到.c文件中,在.h中重新定一个一个typedef,模拟CPP对class的封装。
大致实现如下,100行以内就可以实现:)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
struct vector {
size_t item_size;
unsigned int item_num;
unsigned int item_max_num;
void *head;
};
void ve_push_back(struct vector *ve, const void *item)
{
if (ve->item_num == ve->item_max_num) {
unsigned int old_len = ve->item_size * ve->item_num;
ve->item_max_num += ve->item_max_num >> 1u;
void *new_array = malloc(ve->item_size * ve->item_max_num);
if (new_array == NULL) {
printf("malloc failed");
return;
}
memcpy(new_array, ve->head, old_len);
free(ve->head);
ve->head = new_array;
}
void *last = (char *) ve->head + ve->item_num * ve->item_size;
memcpy(last , item, ve->item_size);
ve->item_num++;
}
void ve_erase(struct vector *ve, void *item)
{
if (item == NULL) {
printf("erase nullptr\n");
return;
}
char *last = (char *) ve->head + ve->item_size * (ve->item_num - 1);
if (last < (char*)item) {
printf("erase item out of range\n");
return;
}
if (item < ve->head) {
printf("erase item addr invalid, < first item\n");
return;
}
ve->item_num--;
if ((char*)item < last ) {
memmove(item, (char *) item + ve->item_size, last - (char *) item);
}
}
// return true if item1 equals item2
typedef bool (ve_comp_func)(const char *item1, const char *item2);
void *ve_find(struct vector *ve, const void *item, ve_comp_func comp)
{
unsigned int i;
for (i = 0; i < ve->item_num; i++) {
char *cur = (char*)ve->head + i * ve->item_size;
if (comp((char*)item, cur)) {
return cur;
}
}
return NULL;
}
void ve_init(struct vector *ve, size_t item_size)
{
ve->item_max_num = 10;
ve->head = malloc(ve->item_max_num * item_size);
if (ve->head == NULL) {
printf("malloc failed\n");
return;
}
ve->item_size = item_size;
ve->item_num = 0;
}
void ve_clear(struct vector *ve)
{
free(ve->head);
memset(ve, 0, sizeof(*ve));
}
//--------- test case ------------------
// an int vector
bool comp(const char *item1, const char *item2)
{
return *(int*)item1 == *(int*)item2;
}
void show_re(struct vector *ve)
{
unsigned int i;
int *data = (int *) ve->head;
for (i = 0; i < ve->item_num; i++) {
printf("%d ", data[i]);
}
printf("\n");
}
int main()
{
int n = 0;
struct vector ve;
ve_init(&ve, sizeof(int));
while (n != -1) {
scanf("%d", &n);
ve_push_back(&ve, &n);
show_re(&ve);
}
while (n != -2) {
scanf("%d", &n);
void *item = ve_find(&ve, &n, comp);
ve_erase(&ve, item);
show_re(&ve);
}
ve_clear(&ve);
return 0;
}
构造的测试用例,可以从键盘获取输入来测试。