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 testTests 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.