Lesson 3 · 3 of 20
realloc and a growing array · C
Build a dynamic array in C that grows with realloc, doubling its capacity, to store sensor readings without knowing how many will arrive.

Often you do not know how much data will arrive: readings from a sensor, lines in a file. The answer is a dynamic array: the Readings struct keeps the pointer to the data, how many are used (len) and how many fit (cap).
push adds a value. If the array is full (len == cap), it asks for more room with `realloc`, which grows the block or copies it into a bigger one and returns the new address. The capacity doubles (2, 4, 8, 16), so there are few allocations even when thousands of values are added.
The result of realloc goes into bigger first, not straight into r->data. If realloc fails it returns NULL but the old block is still valid; with r->data = realloc(r->data, …) you would lose the only address that can free it.
temps starts with NULL and capacity 0: realloc(NULL, n) behaves like malloc(n), so the first allocation needs no special case. The grow: lines in the output show each time the array grew.
At the end one free(temps.data) is enough, because everything is in a single block. If push fails, main frees what it already had before leaving.
Code · main.c
#include <stdio.h>#include <stdlib.h>// A growing array: the data, how many are used and how many fit.typedef struct { double *data; size_t len, cap; } Readings;int push(Readings *r, double value) { if (r->len == r->cap) { size_t new_cap = r->cap ? r->cap * 2 : 2; // realloc into a temporary: if it fails, the old block is still ours. double *bigger = realloc(r->data, new_cap * sizeof *bigger); if (bigger == NULL) return 0; printf(" grow: %zu -> %zu\n", r->cap, new_cap); r->data = bigger; r->cap = new_cap; } r->data[r->len++] = value; return 1;}int main(void) { Readings temps = {NULL, 0, 0}; // realloc(NULL, n) works like malloc(n) double sensor[] = {18.5, 19.0, 20.25, 21.0, 22.5, 21.75, 20.0, 19.5, 18.0}; for (size_t i = 0; i < sizeof sensor / sizeof sensor[0]; i++) if (!push(&temps, sensor[i])) { free(temps.data); return 1; } double sum = 0; for (size_t i = 0; i < temps.len; i++) sum += temps.data[i]; printf("%zu readings, capacity %zu, average %.2f\n", temps.len, temps.cap, sum / temps.len); free(temps.data); return 0;}Output · cc main.c -o main && ./main
grow: 0 -> 2 grow: 2 -> 4 grow: 4 -> 8 grow: 8 -> 16 9 readings, capacity 16, average 20.06
Key points
- A dynamic array keeps data, length and capacity.
- Doubling the capacity avoids a
reallocfor every value. - Store the result of
reallocin a temporary variable. realloc(NULL, n)is the same asmalloc(n).
Exercise
Add a pop function that removes and returns the last reading and, when len drops to a quarter of cap, halves the capacity with realloc.