stb_vector is a single-header, type-safe, generic dynamic array library for C (also compatible with C++). Inspired by the stb libraries philosophy, it provides easy-to-use dynamic arrays similar to C++ std::vector with modern safety features and zero external dependencies.
- Features
- Why stb_vector?
- Quick Start
- Installation
- API Reference
- Building Examples
- Running Tests
- Comparison with C++ std::vector
- Performance
- Safety Features
- Thread Safety
- Custom Types
- Configuration
- License
- π― Type-Safe: Generic programming with compile-time type checking
- π¦ Single Header: Just drop
stb_vector.hinto your project - π‘οΈ Memory Safe: Bounds checking, use-after-free detection, allocation failure handling
- β‘ Fast: O(1) amortized push, cache-friendly contiguous storage
- π§ Easy to Use: Clean API similar to C++ vectors
- π¨ Exception Handling: Try/catch style error handling using setjmp/longjmp
- π§΅ Thread-Aware: Thread-local error contexts for multi-threaded environments
- π No Dependencies: Pure C with standard library only
- π Portable: Works on Windows, Linux, macOS, Unix (32/64-bit)
- π C++ Compatible: Works seamlessly in C++ projects
C doesn't have built-in dynamic arrays. Traditional solutions involve:
- Manual memory management - Error-prone malloc/realloc/free
- Unsafe macros - Type-unsafe, hard to debug
- Complex libraries - Heavy dependencies, steep learning curve
stb_vector brings C++-style vectors to C with:
- β Type safety without templates
- β Automatic memory management
- β
Familiar API (like
std::vector) - β Single-header simplicity
- β Production-ready error handling
#define STB_VECTOR_IMPLEMENTATION
#include "stb_vector.h"
#include <stdio.h>
int main(void) {
// Create a new integer vector
Vector(int) *vec = vector_new(int);
// Add elements
$(vec)->push_back(10);
$(vec)->push_back(20);
$(vec)->push_back(30);
// Access elements
printf("Size: %zu\n", $(vec)->size());
printf("First: %d\n", $(vec)->front());
printf("Last: %d\n", $(vec)->back());
// Iterate
for (size_t i = 0; i < $(vec)->size(); ++i) {
printf("%d ", $(vec)->get(i));
}
printf("\n");
// Cleanup
$(vec)->destroy();
free(vec);
return 0;
}Output:
Size: 3
First: 10
Last: 30
10 20 30
- Download
stb_vector.h - Copy it to your project directory
- Include it in ONE C file with the implementation:
#define STB_VECTOR_IMPLEMENTATION
#include "stb_vector.h"- In other files, just include without the define:
#include "stb_vector.h"git clone https://github.com/haseeb-heaven/stb_vector.git
cd stb_vector
mkdir build && cd build
cmake ..
makeVector(T) *vec = vector_new(T); // Empty vector
Vector(T) *vec = vector_new(T, 10); // Pre-sized (10 elements, zero-initialized)
Vector(T) *vec = vector_new(T, 10, value); // Pre-filled (10 elements, all = value)| Function | Description | Complexity |
|---|---|---|
$(vec)->push_back(value) |
Add element to end | O(1) amortized |
$(vec)->pop_back() |
Remove last element | O(1) |
$(vec)->insert(idx, value) |
Insert at position | O(n) |
$(vec)->erase(idx) |
Remove at position | O(n) |
$(vec)->set(idx, value) |
Set element at index | O(1) |
$(vec)->resize(new_size) |
Change size | O(n) if growing |
$(vec)->reserve(capacity) |
Reserve capacity | O(n) if growing |
$(vec)->clear() |
Remove all elements | O(1) |
| Function | Description | Complexity |
|---|---|---|
$(vec)->get(idx) |
Get element at index | O(1) |
$(vec)->at(idx) |
Alias for get() |
O(1) |
$(vec)->front() |
Get first element | O(1) |
$(vec)->back() |
Get last element | O(1) |
$(vec)->data_ptr() |
Get raw pointer to data | O(1) |
| Function | Description |
|---|---|
$(vec)->size() |
Current number of elements |
$(vec)->capacity() |
Allocated capacity |
$(vec)->empty() |
Check if empty |
$(vec)->max_size() |
Maximum possible size |
| Function | Description |
|---|---|
$(vec)->shrink_to_fit() |
Release unused memory |
$(vec)->swap(other_vec) |
Swap with another vector (O(1)) |
$(vec)->destroy(); // Free internal data
free(vec); // Free the struct itselfmkdir build && cd build
cmake ..
make
# Run examples
./examples/example_c
./examples/example_cpp
# Run tests
./tests/test_vectorC Example:
gcc -o example_c examples/example_c.c -I. -std=c99
./example_cC++ Example:
g++ -o example_cpp examples/example_cpp.cpp -I. -std=c++11
./example_cppcd build
make
./tests/test_vectorTests cover:
- β Creation and destruction
- β Push/pop operations
- β Insert/erase
- β Resizing and reserving
- β Bounds checking
- β Error handling
- β Edge cases (empty vector, large sizes)
- β Memory leak detection
stb_vector is designed to be conceptually similar to C++ std::vector, making it intuitive for C++ developers working in C.
| Feature | std::vector | stb_vector |
|---|---|---|
| Dynamic array | β | β |
| Type-safe | β | β |
| Automatic memory management | β | β |
| Bounds checking (at) | β | β |
| push_back, pop_back | β | β |
| insert, erase | β | β |
| size, capacity | β | β |
| resize, reserve | β | β |
| front, back | β | β |
| clear, empty | β | β |
| shrink_to_fit | β | β |
| swap | β | β |
| Aspect | std::vector | stb_vector |
|---|---|---|
| Language | C++ | C (C++ compatible) |
| Implementation | Template | Macro-generated |
| Element access | vec[i] or vec.at(i) |
$(vec)->get(i) |
| Iterators | β (full iterator support) | β (use indices) |
| Range-based for | β | β (use index loop) |
| Move semantics | β (C++11+) | N/A |
| Exception handling | C++ exceptions | setjmp/longjmp |
| Context binding | Automatic | $(vec) macro |
C++ std::vector:
std::vector<int> vec;
vec.push_back(10);
vec.push_back(20);
std::cout << vec[0] << std::endl;
for (int x : vec) {
std::cout << x << " ";
}C++ stb_vector:
Vector(int) *vec = vector_new(int);
$(vec)->push_back(10);
$(vec)->push_back(20);
std::cout << $(vec)->get(0) << std::endl;
for (size_t index = 0; index < $(vec)->size(); ++index) {
std::cout << $(vec)->get(index) << " ";
}
$(vec)->destroy();
free(vec);| Operation | Complexity | Notes |
|---|---|---|
push_back |
O(1)* | *Amortized (2x growth factor) |
pop_back |
O(1) | |
get/set |
O(1) | Direct array access |
insert |
O(n) | Shifts elements |
erase |
O(n) | Shifts elements |
resize |
O(n) | Only if growing |
clear |
O(1) | Just resets size |
- Per-vector overhead: ~40 bytes (struct metadata)
- Growth strategy: Exponential (2x doubling)
- Memory layout: Contiguous array (cache-friendly)
On a typical modern CPU (x86_64):
- 1M push_back operations: ~5-10ms
- Random access (1M gets): ~2-3ms
- Resize to 1M elements: ~5-8ms
(Actual performance depends on hardware, compiler optimizations, and data types)
All access operations validate indices:
Vector(int) *vec = vector_new(int);
$(vec)->get(10); // ERROR: Out of boundsMagic number validation:
$(vec)->destroy();
$(vec)->push_back(10); // ERROR: Invalid vector (magic number check fails)Graceful error reporting:
stb_try(vec) {
$(vec)->reserve(SIZE_MAX); // Will fail
} stb_catch {
printf("Error: %s\n", vec->error.message);
}stb_try(vec) {
$(vec)->push_back(10);
$(vec)->get(100); // Throws exception
// Code below doesn't execute
} stb_catch {
printf("Caught: %s\n", vec->error.message);
}- Different vectors in different threads: Fully safe
- Thread-local error contexts: Each thread has its own error state
- Sharing same vector across threads: Requires external synchronization (mutex)
Example:
// Thread 1
Vector(int) *vec1 = vector_new(int);
$(vec1)->push_back(10); // β
Safe
// Thread 2
Vector(int) *vec2 = vector_new(int);
$(vec2)->push_back(20); // β
Safe
// Thread 1 and 2 accessing vec1
// β NOT SAFE without mutexYou can use stb_vector with custom types:
typedef struct {
int x;
int y;
} Point;
// Declare vector for Point type
DECLARE_VECTOR(Point)
// Usage
Vector(Point) *points = vector_new(Point);
Point p = {10, 20};
$(points)->push_back(p);Built-in types: int, float, double, char, long
You can customize memory allocation:
#define STB_VECTOR_MALLOC(sz, ctx) my_malloc(sz)
#define STB_VECTOR_REALLOC(ptr, sz, ctx) my_realloc(ptr, sz)
#define STB_VECTOR_FREE(ptr, ctx) my_free(ptr)
#define STB_VECTOR_IMPLEMENTATION
#include "stb_vector.h"Other configuration:
STB_VECTOR_INITIAL_CAPACITY(default: 1)STB_VECTOR_GROWTH_FACTOR(default: 2)
This software is dual-licensed. Choose whichever you prefer:
Copyright (c) 2025 Haseeb Mir
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software.
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
git clone https://github.com/haseeb-heaven/stb_vector.git
cd stb_vector
mkdir build && cd build
cmake ..
make
make testInspired by:
- stb libraries by Sean Barrett
- C++ STL
std::vector
Author: Haseeb Mir
Version: 1.0
Repository: https://github.com/haseeb-heaven/stb_vector
Made with β€οΈ for the C community