C语言无内置vector因标准库不支持动态数组,需手动管理内存;stb_ds.h等库用宏封装实现高效、轻量的vector功能。
C 标准库不提供动态数组容器(如 C++ 的 std::vector),所有数组长度必须编译期确定或手动管理内存。当需要在运行时增删元素、自动扩容时,malloc/realloc + 手动维护长度/容量是唯一选择——这也是“Vector C”类库(如 kcvec、vec.h、stb_ds)存在的根本原因:把重复的内存管理逻辑封装成可复用的宏或函数集。
stb_ds.h 快速声明和操作 vectorstb_ds.h 是最轻量、头文件即用的 C vector 实现,靠宏展开生成类型专用代码,无运行时开销。它不依赖任何外部库,只需包含单个头文件。
常见操作对应关系:
int *arr = NULL; → 声明空 vector(指针初始化为 NULL)arr_push(arr, 42); → 尾部插入,自动扩容arr_pop(arr); → 移除并返回最后一个元素arr_len(arr) → 当前元素个数(不是分配字节数)arr_free(arr); → 释放全部内存,指针置为 NULL
#include "stb_ds.h"int main() { int *v = NULL; arr_push(v, 10); arr_push(v, 20); arr_push(v, 30); printf("len: %d, last: %d\n", arr_len(v), v[arr_len(v)-1]); // len: 3, last: 30 arr_free(v); return 0; }
自己实现类似 vec_push 的宏,看似简单,实际极易出错。核心问题不在逻辑,而在宏展开时机与副作用。
vec_push 参数里放带副作用的表达式:比如 vec_push(v, i++) 可能导致 i 被计算两次(一次判断容量,一次赋值)
O(n²) 插入复杂度realloc 返回值是否为 NULL:失败时不更新原指针,否则造成内存泄漏+悬垂指针一个安全的手写片段示意(仅展示关键判断逻辑):
#define vec_push(vec, elem) do { \
typeof(*(vec)) *_vec = (vec); \
size_t _len = vec ? vec_len(vec) : 0; \
size_t _cap = vec ? vec_cap(vec) : 0; \
if (_len >= _cap) { \
size_t new_cap = _cap ? _cap * 2 : 1; \
typeof(*(vec)) *_new = realloc(_vec, new_cap * sizeof(*(vec))); \
if (!_new) abort(); /* 或返回错误码 */ \
(vec) = _new; \
vec_set_cap(vec, new_cap); \
} \
(vec)[_len] = (elem); \
vec_set_len(vec, _len + 1); \
} while(0)vector 本质是尾部高效、随机访问快、头部/中间插入极慢的结构。如果你的场景频繁在开头加元素、按条件删除中间项、或需要稳定迭代器,它反而会掩盖性能问题。
list.h 或手写 struct node *)uthash.h)或先标记再批量 compact真正难的从来不是“怎么让 vector 工作”,而是“它是不是当前问题最合适的抽象”。很多 C 项目后期性能瓶颈,追根溯源都是早期把 vector 当万能胶水,往不该塞的地方硬塞。