Foundations · Two-dimensional arrays
A matrix is one flat line, folded into rows
Memory has no rows. M[r][c] is arithmetic — cell number r × n + c in a single block. Learn that one formula and the nested loops, the traversal order and the transposes all fall out of it.
Walk the same 3 × 3 two different ways →01 The idea
Two indices, one straight line of memory
A 2-D array is a block of values you reach with two numbers instead of one. You picture a grid: m rows across n columns, and M[r][c] is the cell where row r meets column c. Memory does not have that shape. It is one long line of storage, so the language has to fold your grid into that line, and it folds it row by row. Row 0 is laid down first, then row 1 immediately after it, then row 2. That layout is called row-major order.
Once you can see the fold, the nested loop writes itself. The outer loop chooses which row you are on. The inner loop walks that row from column 0 to column n − 1, and then the outer loop moves you down one. Swap those two loops and you still touch all m × n cells, but you meet them in a different order — and a surprising number of interview questions are really about that order.
02 Worked example
Row sums of a 3 × 3, one cell at a time
Take the matrix 4 1 3 / 2 5 0 / 6 2 1 — three rows, three columns, and it stays on screen for the rest of this lesson. The job is one number per row: the sum of that row's three cells. Walk it in row-major order, which means finish a row before you start the next, and keep a running sum that resets when the row changes. The rose cells are the nine values being read; the green row at the bottom is what you end up storing.
Two things to carry forward. First, the running sum belongs to the outer loop: it is created once per row, reset before the inner loop starts, and stored when the inner loop ends. Move that reset into the inner loop and every row sum collapses to the last cell of its row — you would store 3, 0, 1. Move it above the outer loop and the sum never restarts, so you store running totals 8, 15, 24: still three numbers, but each one is every row up to that point, and only the last is the grand total 24. Second, look at the order the nine cells were read: 4, 1, 3, 2, 5, 0, 6, 2, 1. That is exactly the order they sit in memory, because the matrix was stored row after row.
03 Mechanics
Same nine cells, two different walks
The two versions below differ in exactly one thing: which loop is on the outside. On the left the outer loop picks a row and the inner walks its columns, so you get row sums. On the right the outer loop picks a column and the inner walks its rows, so you get column sums. Both read all nine cells exactly once, and both totals come to 24.
Row-major — one sum per row
for r = 0 to m-1: // pick a row sum = 0 for c = 0 to n-1: // walk it sum = sum + M[r][c] rowSum[r] = sum
Column-major — one sum per column
for c = 0 to n-1: // pick a column sum = 0 for r = 0 to m-1: // walk it sum = sum + M[r][c] colSum[c] = sum
The outer loop names what you are counting. In the left version sum belongs to a row, so it resets whenever r changes and there are m answers. In the right version it belongs to a column and there are n. If you are summing the wrong thing, the loop order is the bug — not the arithmetic inside.
The visit order changes, the total does not. Row-major reads 4, 1, 3, 2, 5, 0, 6, 2, 1. Column-major reads 4, 2, 6, 1, 5, 2, 3, 0, 1. Nine reads either way, 24 either way, because addition does not care about order. What differs is which subtotals you end up holding: the three row sums 8, 7, 9 on the left against the three column sums 12, 8, 4 on the right. Both triples add to 24.
Row-major is the faster walk on a row-major array. Consecutive cells in the left version are neighbours in memory, so one cache-line fetch serves several reads. The right version jumps n elements per step and can pay a fresh memory fetch on every read. Both are O(m × n) — the difference is wall-clock time on a big matrix, not step count.
05 Cheat sheet
What gets asked about an m × n matrix
| Operation | Cost | Why |
|---|---|---|
| Read or write M[r][c] | O(1) | One multiply and one add: the address is base + (r × n + c) × size. |
| Visit every cell | O(m × n) | Nothing beats it. There are that many cells and each has to be touched once. |
| Sum one row | O(n) | n cells, and they sit next to each other in memory. |
| Sum one column | O(m) | m cells, each one n elements away from the last. |
| All row sums (section 03) | O(m × n) | The full nest, plus O(m) extra space to hold the answers. |
| Transpose an n × n in place | O(n²) | Swap M[r][c] with M[c][r] for every c > r — that is n(n−1)/2 swaps and O(1) extra space. |
06 Where & why
When a rectangle is the right shape
A 2-D array buys you constant-time access to any cell and the tightest memory layout there is. The price is fixed and paid up front: m × n cells are allocated whether you fill them or not, and the rectangle cannot change shape once it exists.
Reach for one when…
Use something else when…
| Situation | Better choice | Why |
|---|---|---|
| Rows have different lengths | A jagged array — a list of rows | A rectangle has to be padded out to the widest row, and r × n + c stops being the address of anything. |
| Almost every cell is zero | A hash map keyed by (r, c), or CSR sparse format | A 10⁵ × 10⁵ matrix is 10¹⁰ cells. You cannot allocate it, and you would be storing zeros in almost all of it. |
| You are modelling a sparse graph | An adjacency list | An adjacency matrix costs O(V²) space, and "list my neighbours" becomes O(V) instead of O(degree). |
| The grid grows while the program runs | A dynamic array of dynamic rows, e.g. vector<vector<int>> | A fixed rectangle has to be reallocated and copied whole to add a single row. |
07 Interview questions
What they actually ask
Matrix questions turn up in every first round, and half of them are really testing whether you know that M[r][c] is a formula rather than a magic pair of brackets.
What is a 2-D array?
What does row-major order mean?
Give me the address of M[r][c].
You have a flat index k into a 1-D array. How do you read it as a grid?
Row-major and column-major traversal both do m × n reads. Why is one faster?
Which loop should be the outer one?
What is a jagged array?
Is int a[3][4] in C an array of pointers?
How do you sum one column, and what does it cost?
How do you transpose a square matrix in place?
Rotate a matrix 90 degrees clockwise — how?
Where would you actually use a 2-D array?
08 Practice problems
Six that live inside one nested loop
Use the 3 × 3 from section 02 as your test case for every one of these. If a solution does not give the right answer on nine cells you can check by hand, it will not give the right answer on nine hundred.