A production-ready, macro-based vector library to generate type-safe dynamic arrays.
#include "vector.h" /* Arguments are: vector name, func. prefix, and input type */ VECTOR_DECLARE(IntVector, int_vector, int) VECTOR_DEFINE(IntVector, int_vector, int) int main(void) { IntVector nums = {0}; int_vector_push(&nums, 42); int_vector_push(&nums, 13); printf("First: %d\n", int_vector_get(&nums, 0)); /* 42 */ printf("Size: %zu\n", VECTOR_SIZE(&nums)); /* 2 */ int_vector_free(&nums); return 0; }
- Type-safe: Generate vectors for any type
- Portable: C89 compatible, tested on GCC/Clang/MSVC/ICX across x86/x86_64/ARM64
- Robust: Comprehensive bounds checking and memory management
- Configurable: Custom allocators, null-pointer policies
- Zero dependencies: Just standard C library
- Include the header and declare your vector type:
/* my_vector.h */ #include "vector.h" VECTOR_DECLARE(MyVector, my_vector, float)
- Define the implementation (usually in a .c file):
#include "my_vector.h" VECTOR_DEFINE(MyVector, my_vector, float)
- Use it:
MyVector v = {0}; my_vector_push(&v, 3.14f); my_vector_push(&v, 2.71f); /* Fast iteration */ for (float *f = v.begin; f != v.end; f++) { printf("%.2f ", *f); } my_vector_free(&v);
Alternatively, if you plan to use your vector within a single file, you can do:
#include "vector.h" VECTOR_DECLARE(MyVector, my_vector, float) VECTOR_DEFINE(MyVector, my_vector, float)
VECTOR_SIZE(vec)- Get element countVECTOR_CAPACITY(vec)- Get allocated capacityvector_push(vec, value)- Append element (O(1) amortized)vector_pop(vec)- Remove and return last elementvector_get(vec, idx)/vector_set(vec, idx, value)- Random accessvector_insert(vec, idx, value)/vector_delete(vec, idx)- Insert/remove at indexvector_clear(vec)- Remove all elementsvector_free(vec)- Deallocate memory
Define before including the library:
#define VECTOR_NO_PANIC_ON_NULL 1 /* Return silently on NULL instead of panic */ #define VECTOR_NO_PANIC_ON_OOB 1 /* Turns out-of-bounds access into no-ops instead of panic */ #define VECTOR_NO_PANIC_ON_OVERFLOW 1 /* Turns capacity overflow into no-ops instead of panic */ #define VECTOR_REALLOC my_realloc /* Custom allocator */ #define VECTOR_FREE my_free /* Custom deallocator */
mkdir build cmake -S . -B build/ -DCMAKE_BUILD_TYPE=Debug cd build make test
Tests cover normal operation, edge cases, out-of-memory conditions, and null pointer handling.
Why vector.h Over stb_ds.h?
- Just as convenient: Both are single-header libraries
- Enhanced type safety: Unlike stb_ds.h, vector.h provides compile-time type checking
- Optimized iteration: vector.h uses the same iteration technique as std::vector, while stb_ds.h requires slower index calculations
- Safer memory management: vector.h avoids the undefined behavior that stb_ds.h uses to hide headers behind data
- Superior debugging experience: vector.h exposes its straightforward pointer-based internals, whereas stb_ds.h hides header data from debugging tools
- Robust error handling: vector.h fails fast with clear panic messages on out-of-bounds access, while stb_ds.h silently corrupts memory
- More permissive licensing: vector.h uses BSD0 (no attribution required, unlimited relicensing), which is less restrictive than stb_ds.h's MIT and more universal than its public domain option since the concept doesn't exist in some jurisdictions
Contributors and library hackers should work on vector.in.h instead of
vector.h. It is a version of the library with hardcoded types and function
names. To generate the final library from it, run libgen.py.
This library is licensed under the BSD Zero license.