Multidimensional Arrays

An array of arrays gives you a grid: rows and columns for game boards, spreadsheets, images and matrices. In memory it's still one block, stored row after row.

A 2D array

C
#include <stdio.h>

int main(void) {
    int seats[3][4] = {
        { 1, 0, 0, 1 },
        { 1, 1, 0, 0 },
        { 0, 0, 0, 1 },
    };
    seats[2][1] = 1;   // book row 2, seat 1

    for (int row = 0; row < 3; row++) {
        printf("Row %d: ", row);
        for (int col = 0; col < 4; col++) {
            printf("%c ", seats[row][col] ? 'X' : '.');
        }
        printf("\n");
    }
    return 0;
}
Output
Row 0: X . . X
Row 1: X X . .
Row 2: . X . X

int seats[3][4] is 3 rows, each an array of 4 ints. The first index picks the row, the second the column.

Row-major layout

The rows are stored one after another, so seats[1][0] comes straight after seats[0][3]. That's why looping over rows in the outer loop and columns in the inner loop is the fast order — it reads memory sequentially:

C
#include <stdio.h>

int main(void) {
    int grid[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
    long gap = (char *) &grid[1][0] - (char *) &grid[0][2];
    printf("grid[1][0] starts %ld bytes after grid[0][2]\n", gap);
    printf("one row: %zu bytes, whole grid: %zu bytes\n", sizeof grid[0], sizeof grid);
    return 0;
}
Output
grid[1][0] starts 4 bytes after grid[0][2]
one row: 12 bytes, whole grid: 24 bytes

Passing to functions

A function receiving a 2D array must know every dimension except the first, so it can work out where each row starts:

C
#include <stdio.h>

#define COLS 3

int row_sum(const int m[][COLS], int row) {
    int total = 0;
    for (int c = 0; c < COLS; c++) total += m[row][c];
    return total;
}

void print_matrix(int rows, const int m[][COLS]) {
    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < COLS; c++) printf("%4d", m[r][c]);
        printf("   | sum %d\n", row_sum(m, r));
    }
}

int main(void) {
    int sales[4][COLS] = { { 5, 3, 8 }, { 2, 9, 4 }, { 7, 7, 1 }, { 0, 6, 3 } };
    print_matrix(4, sales);
    return 0;
}
Output
   5   3   8   | sum 16
   2   9   4   | sum 15
   7   7   1   | sum 15
   0   6   3   | sum 9

For grids whose size is only known at run time, a common approach is a single 1D block of rows * cols elements allocated with malloc, indexed as m[r * cols + c].

Matrix multiplication

C
#include <stdio.h>

int main(void) {
    int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
    int b[3][2] = { { 7, 8 }, { 9, 10 }, { 11, 12 } };
    int product[2][2] = { 0 };

    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 2; j++)
            for (int k = 0; k < 3; k++)
                product[i][j] += a[i][k] * b[k][j];

    for (int i = 0; i < 2; i++) printf("%4d %4d\n", product[i][0], product[i][1]);
    return 0;
}
Output
  58   64
 139  154

Arrays of strings

A 2D char array holds several fixed-size strings; an array of pointers to string literals is the usual alternative when the strings never change:

C
#include <stdio.h>
#include <string.h>

int main(void) {
    char names[3][12] = { "Ana", "Bartholomew", "Cy" };
    const char *days[] = { "Mon", "Tue", "Wed" };
    strcpy(names[2], "Cyrus");
    for (int i = 0; i < 3; i++) printf("%-12s %s\n", names[i], days[i]);
    return 0;
}
Output
Ana          Mon
Bartholomew  Tue
Cyrus        Wed

Each row needs room for the longest string plus its terminating '\0' character (lesson 28): "Bartholomew" has 11 letters, so the rows are 12 characters wide. A row of 10 would leave no room for the terminator, and printing that name would run on into the next row.

Three or more dimensions

The idea extends naturally: double temps[12][31][24] could hold an hourly temperature for every day of a year. In practice more than two dimensions is rare, and a struct is often clearer.

Try it yourself

Play noughts and crosses: given a board, check every row, column and diagonal for a winner.

Try it yourself · main.c
Edit the code, copy it into main.c, then compile and run it with cc -std=c17 -Wall main.c -o main && ./main. How to set up a C compiler
Output
Winner: X