C/C++ Arena

Step 7 of 10

A 2D grid on the heap

Sometimes you need a 2D grid whose size is only known at run time, like a game board read from input. A common way to build one is an array of row pointers: first allocate an array of pointers (one per row), then allocate each row separately.

grid ──> [ row0 ] ──> [ 0 0 0 0 ]
         [ row1 ] ──> [ 0 0 0 0 ]
         [ row2 ] ──> [ 0 0 0 0 ]

grid has type int **: a pointer to the first of several int *, each pointing at a row of ints. grid[r] is row r (an int *), and grid[r][c] is a cell, just like a normal 2D array.

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

int main(void) {
    int rows = 2, cols = 3;
    double **m = malloc(rows * sizeof *m);
    if (!m) return 1;
    for (int r = 0; r < rows; r++) {
        m[r] = malloc(cols * sizeof *m[r]);
        if (!m[r]) {
            for (int k = 0; k < r; k++) free(m[k]);
            free(m);
            return 1;
        }
        for (int c = 0; c < cols; c++) m[r][c] = r + c / 10.0;
    }
    printf("%.1f %.1f\n", m[0][2], m[1][1]);
    for (int r = 0; r < rows; r++) free(m[r]);
    free(m);
    return 0;
}
0.2 1.1

Cleaning up

Free in reverse order of creation: every row first, then the array of row pointers. If you freed m first, you'd lose the pointers to the rows and leak them all.

When an allocation fails halfway

If row 2 of 5 fails, rows 0 and 1 are already allocated. Returning NULL without freeing them would leak. The example handles it: free every row made so far, then the pointer array, then report failure. Handling partial failure is a big part of writing robust C.

(Another layout is one big block of rows * cols cells indexed as cells[r * cols + c]: a single allocation and usually faster, but less convenient.)

Your turn: write make_grid (all cells zero) and free_grid.

Previous: Memory bugs to avoid Next: Who owns what