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.