首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言實現泛型編程:基於 void* 的類型擦除向量容器完整實現

     編輯:關於C語言

核心思想

C 無模板/泛型語法,但可通過 void* 類型擦除 + 顯式傳遞元素大小,實現類似 C++ vector<T> 的泛型容器。關鍵點:

  • 容器存儲 void**(指針數組),每個元素單獨 malloc
  • 操作函數接收 size_t elem_size 參數
  • 迭代器類型為 void**,使用時強轉回具體類型

接口設計:vector.h


#ifndef VECTOR_H
#define VECTOR_H

typedef struct vector *Vector;          // 不透明指針,封裝實現
typedef void **vec_iterator;            // 迭代器類型

Vector vec_construct(size_t elem_size); // 構造,指定元素大小
void vec_destruct(Vector v);            // 析構
size_t vec_size(Vector v);              // 元素數量
vec_iterator vec_begin(Vector v);       // 首元素迭代器
vec_iterator vec_end(Vector v);         // 尾後迭代器
void vec_insert_n(Vector v, vec_iterator pos, size_t n, const void *elem); // 批量插入
void vec_push_back(Vector v, const void *elem); // 尾部插入

#endif

核心實現:vector.c

內部結構


struct vector {
    void **start;        // 數據區起始
    void **finish;       // 已用區末尾
    void **end_of_storage; // 容量末尾
    size_t elem_size;    // 單個元素大小
};

構造/析構


Vector vec_construct(size_t elem_size) {
    Vector v = malloc(sizeof(struct vector));
    v->start = v->finish = v->end_of_storage = NULL;
    v->elem_size = elem_size;
    return v;
}

void vec_destruct(Vector v) {
    for (void **it = v->start; it != v->finish; ++it)
        free(*it);           // 釋放每個元素內存
    free(v->start);          // 釋放指針數組
    free(v);
}

擴容與插入核心邏輯


void vec_insert_n(Vector v, vec_iterator pos, size_t n, const void *elem) {
    if (n == 0) return;
    
    size_t old_size = v->finish - v->start;
    size_t new_size = old_size + n;
    size_t insert_idx = pos - v->start;
    
    // 擴容檢查:剩餘空間 < n
    if (v->end_of_storage - v->finish < n) {
        size_t new_cap = old_size + (old_size > n ? old_size : n); // 2倍或按需
        void **new_base = realloc(v->start, new_cap * sizeof(void*));
        v->start = new_base;
        v->end_of_storage = v->start + new_cap;
    }
    
    v->finish = v->start + new_size;
    void **old_finish = v->start + old_size;
    pos = v->start + insert_idx; // 重新計算,因 realloc 可能移動內存
    
    // 向後移動元素 [pos, old_finish) → [pos+n, old_finish+n)
    for (void **it = old_finish + n - 1; it >= pos + n; --it)
        *it = *(it - n);
    
    // 插入 n 份拷貝
    for (void **it = pos + n - 1; it >= pos; --it) {
        *it = malloc(v->elem_size);
        memcpy(*it, elem, v->elem_size);
    }
}

void vec_push_back(Vector v, const void *elem) {
    vec_insert_n(v, vec_end(v), 1, elem);
}

類型專用輸出包裝


void print_char_vec(Vector v) {
    for (void **it = vec_begin(v); it != vec_end(v); ++it)
        printf("%c\n", *(char *)*it); // void** → char* → char
}

void print_double_vec(Vector v) {
    for (void **it = vec_begin(v); it != vec_end(v); ++it)
        printf("%.2f\n", *(double *)*it); // void** → double* → double
}

測試主程序


void test_char() {
    Vector v = vec_construct(sizeof(char));
    char c = 'A';
    for (int i = 0; i < 5; ++i) {
        vec_push_back(v, &c);
        ++c;
    }
    print_char_vec(v);
    printf("size: %zu\n", vec_size(v));
    vec_destruct(v);
}

void test_double() {
    Vector v = vec_construct(sizeof(double));
    double d = 3.14;
    for (int i = 0; i < 13; ++i) {
        vec_push_back(v, &d);
        d += 1.0;
    }
    print_double_vec(v);
    printf("size: %zu\n", vec_size(v));
    vec_destruct(v);
}

int main() {
    test_char();
    printf("\n");
    test_double();
    return 0;
}

運行結果


A
B
C
D
E
size: 5

3.14
4.14
5.14
6.14
7.14
8.14
9.14
10.14
11.14
12.14
13.14
14.14
15.14
size: 13

關鍵技術總結

局限與擴展

  • 無編譯期類型檢查,誤用導致運行時崩潰
  • 可添加比較函數指針支持排序、查找
  • 可實現 vec_erase、vec_resize、vec_reserve 等完整 STL 接口
  • C11 _Generic 可提供類型安全包裝宏
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
技術點實現方式
類型擦除元素存為 void*,容器不知具體類型
大小參數化構造時傳入 elem_size,所有操作依賴它
迭代器類型void**,使用時雙重解引用並強轉
內存管理每個元素獨立 malloc/free,容器管理指針數組
擴容策略geometric growth (2x),amortized O(1) push_back