小练习 - C语言实现一个极简通用vector

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;
}

构造的测试用例,可以从键盘获取输入来测试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值