C Academy · Lesson

A Reusable Vector Type

Wrap size and capacity.

Lesson 3 of 413 steps

A Reusable Vector Type is a free C Academy lesson on CoddyKit. This is lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C Academy learning path, and your progress syncs across the web and the CoddyKit app. The C Academy course includes 4 lessons in total.

From Loose Code to a Type

Passing around a pointer, a count, and a capacity as three separate variables is error-prone.

Let's bundle them into one struct: a reusable dynamic array, often called a vector. It packages the data and the bookkeeping together.

The Vector Struct

A vector needs three fields: a pointer to the data, how many elements are used (len), and how many fit before resizing (cap).

typedef struct {
    int    *data;
    size_t  len;
    size_t  cap;
} Vec;

Initializing a Vector

An empty vector has a NULL data pointer and zero length and capacity. A small init function makes the intent clear.

void vec_init(Vec *v) {
    v->data = NULL;
    v->len = 0;
    v->cap = 0;
}

The Push Operation

vec_push adds one element to the end. If the vector is full, it doubles the capacity first.

It returns 0 on success and -1 if allocation fails, so callers can react.

int vec_push(Vec *v, int value) {
    if (v->len == v->cap) {
        size_t nc = v->cap ? v->cap * 2 : 4;
        int *tmp = realloc(v->data, nc * sizeof(*v->data));
        if (!tmp) return -1;
        v->data = tmp;
        v->cap = nc;
    }
    v->data[v->len++] = value;
    return 0;
}

Reading Elements Back

Because len tracks the used count, you iterate from 0 to len - 1. The capacity may be larger, but those slots aren't part of your data yet.

for (size_t i = 0; i < v->len; i++)
    printf("%d\n", v->data[i]);

Freeing the Vector

A vector owns its heap buffer, so it needs a matching cleanup function. After freeing, reset the fields so the struct can't be misused.

void vec_free(Vec *v) {
    free(v->data);
    v->data = NULL;
    v->len = v->cap = 0;
}

Putting It Together

This full program builds a vector, pushes five values, prints them, then frees it cleanly.

#include <stdio.h>
#include <stdlib.h>

typedef struct { int *data; size_t len, cap; } Vec;

int vec_push(Vec *v, int value) {
    if (v->len == v->cap) {
        size_t nc = v->cap ? v->cap * 2 : 4;
        int *tmp = realloc(v->data, nc * sizeof(*v->data));
        if (!tmp) return -1;
        v->data = tmp; v->cap = nc;
    }
    v->data[v->len++] = value;
    return 0;
}

int main(void) {
    Vec v = {0};
    for (int i = 0; i < 5; i++) vec_push(&v, i * 10);
    for (size_t i = 0; i < v.len; i++) printf("%d\n", v.data[i]);
    free(v.data);
    return 0;
}

Zero-Initializing with {0}

Writing Vec v = {0}; sets every field to zero, including the data pointer to NULL.

This is a handy shortcut that makes a vector ready for vec_push without calling an explicit init function.

Vec v = {0};      /* data=NULL, len=0, cap=0 */
vec_push(&v, 42);

A Safe get Helper

Indexing past len is a bug. A small accessor can check bounds and signal errors, trading a little speed for safety.

int vec_get(const Vec *v, size_t i, int *out) {
    if (i >= v->len) return -1;   /* out of range */
    *out = v->data[i];
    return 0;
}

Why Track len and cap Separately

cap is how much memory is allocated; len is how much you actually use.

Keeping spare capacity means most pushes don't call realloc. This separation is what makes a vector both fast and flexible.

Generalizing the Type

This vector stores int. To hold other types you can change the element type, or store void * with an element size.

The pattern, init, push, free, stays the same regardless of what you store.

typedef struct {
    double *data;
    size_t  len, cap;
} DVec;   /* same shape, different element type */

Quick Check

Test your understanding of the vector type.

Recap

A vector bundles a data pointer, len, and cap into one struct.

vec_push doubles capacity when full, vec_free releases the buffer and resets fields, and {0} initializes cleanly. This reusable pattern beats juggling loose variables. Next: freeing correctly and avoiding leaks.

Free to start

Learn C with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
39
Lessons
144

Frequently Asked Questions

Is the “A Reusable Vector Type” lesson free?

Yes — the full text of “A Reusable Vector Type” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C Academy course, upgrade to CoddyKit PRO. The C Academy course includes 4 lessons in total.

What will I learn in “A Reusable Vector Type”?

Wrap size and capacity. You practise C Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C Academy?

No prior experience is required. C Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

How long does the “A Reusable Vector Type” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C Academy lesson?

Yes. Every C Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Allocating an Array
  2. Growing with realloc
  3. A Reusable Vector Type
  4. Freeing and Avoiding Leaks
← Back to C Academy