Foundations — Multi-dimensional arrays
This page assumes nothing. Before you can trust the parent note Multi-dimensional arrays, you need a handful of small ideas — memory boxes, addresses, sizeof, what a pointer is, what a "type" means, and what the square brackets [] secretly do. We build each from a picture, then show how they stack into the topic.
0. The absolute floor: memory is a numbered street of boxes
Forget arrays. A computer's memory is a long row of tiny boxes, each holding exactly one byte (a byte = a small number, 0–255). Every box has a house number called its address.

Why the topic needs this. The whole parent note is about where a[i][j] lives on this street. If "address" and "base" are fuzzy, the formula is meaningless. Every symbol in that formula is a position on this street.
1. sizeof — how many boxes one value eats
One byte is tiny. Real values need several boxes side by side. An int (a whole number) typically takes 4 boxes; a char takes 1; a double takes 8. This box-count is what the sizeof operator reports.
sizeof(char) // 1
sizeof(int) // 4 (on most machines)
sizeof(double) // 8Why the topic needs it. The address formula counts elements first, then multiplies by to convert to bytes. Without you could count "9 elements past the start" but never turn that into a real house-number. is the elements→bytes exchange rate.
2. Type — the label that tells you the box-count AND the meaning
A type is a promise about a value: how many boxes it uses and how to read those boxes.
Why the topic needs it. The parent says "Type of a is array of 3 arrays of 4 ints". That sentence is doing real work: the type is exactly what tells the compiler how far one a+1 jump moves. Types are the source of all the jump distances.
3. [] on a 1-D array — the square brackets are a counting instruction
Now the first array. Declaring
int x[5]; // five ints in a rowreserves 5 fences of 4 boxes = 20 boxes, all touching. See C Arrays (1D).

Why the topic needs it. int a[3][4] is secretly "an array of 3 things". So a[i] uses this exact rule — except each "element" of a is itself a whole row of 4 ints, so one jump is bigger. Understanding one-index jumps first makes two-index jumps obvious.
4. Pointer — a value that is an address
A pointer is a variable whose stored value is an address (a house-number pointing at another box). See Pointers in C.

Why the topic needs it. The parent's key claim is a[i][j] ≡ *(*(a+i)+j). Every piece of that — the *, the +i, the "jump a whole row" — is exactly pointer arithmetic from this section. And crucially: a+i jumps a row because a has type int(*)[4], a pointer whose element is a 4-int row, so its jump is bytes.
5. ≡ and · and superscripts — the tiny math notations
Three symbols the parent uses without warning:
Why the topic needs it. In addr = base + (i·C + j)·s, the parentheses and dots are the difference between a correct address and garbage. And is what licenses swapping a[i][j] for *(*(a+i)+j) at will.
6. Row-major — the choice of how to flatten a grid
A grid has no built-in "reading order". C picks one: row-major — finish an entire row before starting the next. (Fortran/MATLAB pick the other; see Row-major vs Column-major.)

Why the topic needs it. This choice is why the count is and not something else. Change the flattening rule and the whole address formula changes.
7. Array decay — why a grid quietly becomes a pointer
When you use an array's name in most expressions (or pass it to a function), the name decays into a pointer to its first element. See Array Decay and, for the subtle int (*p)[4] vs int *p[4] split, Pointer to Array vs Array of Pointers.
Why the topic needs it. Decay is the bridge between the declared grid and the pointer formula. It explains the parent's rule "you must pass every dimension except the first": once decayed, only the column count survives in the pointer's type, and is the one thing the address math needs.
The prerequisite map
Equipment checklist
What is an address in memory?
What does sizeof(T), our symbol , tell you?
T occupies — the exchange rate between "element count" and "byte count".Why does a type matter beyond box-count?
Write the 1-D address rule for x[k].
What is a pointer and what does *p do?
*p (dereference) goes to that address and reads the value there.If p has type int*, how many bytes does p + 1 advance?
sizeof(int) bytes (4 on most machines) — one whole element, not one byte.What does mean when we write a[i][j] ≡ *(*(a+i)+j)?
Define row-major order in one sentence.
When int a[3][4] decays, what pointer type do you get and why does a+1 jump 16 bytes?
int(*)[4] (pointer to a 4-int row); adding 1 advances one whole row = bytes.Why does the address formula use the column count but never the row count ?
a[i][j] you skip full rows of elements then more — the arithmetic contains but has no place for .Connections
- Multi-dimensional arrays — the parent this page prepares you for.
- C Arrays (1D) — the single-index rule these all build on.
- Pointers in C — addresses stored as values; dereferencing.
- Array Decay — how a grid name becomes a pointer.
- Pointer to Array vs Array of Pointers — the
int(*)[4]vsint*[4]distinction. - sizeof Operator — the source of .
- Row-major vs Column-major — the flattening choice C makes.
- Variable Length Arrays (C99) — where the "pass the column" rule reappears.