How to replicate vector in c?

Vector and list aren’t conceptually tied to C++. Similar structures can be implemented in C, just the syntax (and error handling) would look different. For example LodePNG implements a dynamic array with functionality very similar to that of std::vector. A sample usage looks like:

uivector v = {};
uivector_push_back(&v, 1);
uivector_push_back(&v, 42);
for(size_t i = 0; i < v.size; ++i)
    printf("%d\n", v.data[i]);
uivector_cleanup(&v);

As can be seen the usage is somewhat verbose and the code needs to be duplicated to support different types.

nothings/stb gives a simpler implementation that works with any types:

double *v = 0;
arrpush(v, 1.0);
arrpush(v, 42.0);
for(int i = 0; i < arrlen(v); ++i)
    printf("%g\n", v[i]);
arrfree(v);

It also provides hash maps, and the trick it uses for type-safe containers in C can be applied to other generic containers too.

Any of these methods can expand the underlying storage either by a call to realloc (see below), or by allocating new storage with malloc and freeing the old one with free — which is equivalent to how std::vector grows its memory in C++.


A lot of C code, however, resorts to managing the memory directly with realloc:

void* newMem = realloc(oldMem, newSize);
if(!newMem) {
    // handle error
}
oldMem = newMem;

Note that realloc returns null in case of failure, yet the old memory is still valid. In such a situation this common (and incorrect) usage leaks memory:

oldMem = realloc(oldMem, newSize);
if(!oldMem) {
    // handle error
}

Compared to std::vector and the C equivalents from above, the simple realloc method does not provide O(1) amortized guarantee, even though realloc may sometimes be more efficient if it happens to avoid moving the memory around.

Leave a Comment