On my computer, the code works for one re-allocation, then it segmentation faults. It's easier to debug when the memory allocation is in one function instead of both init_##vec_name##_c and append_##vec_name. Suggest aA feature of realloc,
allows moving functions around to get one-point-of-failure, for example,
static enum error resize_##vec_name(struct vec_name* vec, size_t min_capacity) { \
size_t new_capacity; \
type* new_items; \
if (!vec) \
return NULL_POINTER_ERROR; \
for (new_capacity = vec->capacity > DEFAULT_CAPACITY \
? vec->capacity : DEFAULT_CAPACITY; \
new_capacity < min_capacity; new_capacity *= EXPAND_RATIO);\
if (vec->capacity >= new_capacity) \
return NO_ERROR; \
new_items = realloc(vec->items, new_capacity * sizeof *new_items); \
if (!new_items) \
return MEMORY_ERROR; \
vec->items = new_items; \
vec->capacity = new_capacity; \
return NO_ERROR; \
} \
Then this simplifies init_##vec_name##_c,
vec->length = 0; \
vec->capacity = 0; \
vec->items = 0; \
return resize_##vec_name(vec, capacity); \
and append_##vec_name,
if((e = resize_##vec_name(vec, vec->length + 1)) != NO_ERROR) \
return e; \
vec->items[vec->length++] = item; \
Viewed as a state machine, your programme has some invalid states. Suggest in free##vec_name,
vec->capacity = vec->length = 0; \