C 無模板/泛型語法,但可通過 void* 類型擦除 + 顯式傳遞元素大小,實現類似 C++ vector<T> 的泛型容器。關鍵點:
void**(指針數組),每個元素單獨 mallocsize_t elem_size 參數void**,使用時強轉回具體類型
#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
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
| 技術點 | 實現方式 |
|---|---|
| 類型擦除 | 元素存為 void*,容器不知具體類型 |
| 大小參數化 | 構造時傳入 elem_size,所有操作依賴它 |
| 迭代器類型 | void**,使用時雙重解引用並強轉 |
| 內存管理 | 每個元素獨立 malloc/free,容器管理指針數組 |
| 擴容策略 | geometric growth (2x),amortized O(1) push_back |