Multidimensional arrays
Represent tables and matrices in C using two-dimensional arrays — declaration, indexing, nested loops, and how they are laid out in memory.
- Declare and initialise a two-dimensional array
- Access elements with row and column indices
- Use nested loops to iterate over all elements
- Explain that 2D arrays are stored in row-major order in memory
A one-dimensional array is a sequence. A two-dimensional array is a table — rows and columns. C supports multidimensional arrays directly, and understanding how they work in memory is important for writing efficient code.
Declaring a 2D array
int matrix[3][4]; /* 3 rows, 4 columns — 12 ints total */The first dimension is the number of rows; the second is the number of columns. With initialisation:
int matrix[2][3] = {
{1, 2, 3}, /* row 0 */
{4, 5, 6} /* row 1 */
};Accessing elements
matrix[1][2] = 99; /* set row 1, column 2 to 99 */
printf("%d\n", matrix[0][1]); /* print row 0, column 1 -- value 2 */matrix[row][col] is the convention. Both indices are zero-based.
Iterating with nested loops
#include <stdio.h>
int main(void) {
int grid[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 4; col++) {
printf("%3d", grid[row][col]);
}
printf("\n");
}
return 0;
}Output:
1 2 3 4
5 6 7 8
9 10 11 12The outer loop traverses rows; the inner traverses columns within each row.
Row-major layout in memory
C stores two-dimensional arrays in row-major order: all elements of row 0 come first in memory, then all elements of row 1, and so on.
grid[0][0] grid[0][1] grid[0][2] grid[0][3]
grid[1][0] grid[1][1] grid[1][2] grid[1][3]
grid[2][0] grid[2][1] grid[2][2] grid[2][3]In memory, they are laid out consecutively:
address: base+0 base+4 base+8 base+12 base+16 base+20 ...
value: 1 2 3 4 5 6 ...This means iterating row by row (outer loop = row, inner loop = col) accesses memory sequentially — which is cache-friendly and fast. Iterating column by column (outer = col, inner = row) jumps around in memory, which is slower on modern CPUs due to cache misses.
Cache locality matters. For large matrices, the difference between row-major iteration and column-major iteration can be 5–10× in performance on real hardware. This is a preview of the memory alignment and CPU cache concepts covered in the Advanced tier.
Passing 2D arrays to functions
Passing 2D arrays requires specifying all dimensions except the first:
void print_matrix(int arr[][4], int rows) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < 4; c++) {
printf("%4d", arr[r][c]);
}
printf("\n");
}
}The column count 4 must be known at compile time so the compiler can compute arr[r][c] as *(arr + r*4 + c). The row count rows can be a parameter.
A practical example: transpose a matrix
#include <stdio.h>
void transpose(int src[][3], int dst[][2], int rows, int cols) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
dst[c][r] = src[r][c];
}
}
}
int main(void) {
int original[2][3] = {{1, 2, 3}, {4, 5, 6}};
int transposed[3][2];
transpose(original, transposed, 2, 3);
for (int r = 0; r < 3; r++) {
printf("%d %d\n", transposed[r][0], transposed[r][1]);
}
return 0;
}Output:
1 4
2 5
3 6Where to go next
Next: C strings — how text is represented in C as null-terminated char arrays, and why this design is both powerful and dangerous.
Arrays: declaration, indexing, and iteration
Store multiple values of the same type in C arrays — declaration, indexing, iteration, and passing arrays to functions.
C strings: char arrays and the null terminator
Understand how C represents text as null-terminated char arrays — declaration, the null terminator, string literals, and basic iteration.