How is a 2-dimensional array stored in memory, and how is an element's address computed?
In row-major order — each full row sits contiguously, then the next row — so addr(A[i][k]) = A + sizeof(T) * (k + N_inner * i).
* Row-major: rows laid end to end; only the inner dimension appears in the address formula. *
C lays out T name[N_outer][N_inner] by flattening it: all of row 0's elements, then all of row 1's, and so on. To reach A[i][k] you skip i whole rows (N_inner elements each), then k elements into that row.
Memory layout (row-major):
name[0][0] name[0][1] ... name[0][N_inner-1] | name[1][0] ...
|------------- row 0 -----------------------| |---- row 1 ...
Address of name[i][k]:
addr = name + s_T * (k + N_inner * i)
The key insight: only N_inner (the inner dimension) appears in the formula — N_outer does not. That's precisely why C lets you write int A[][M] (omit the outer size) as a function parameter, but not int A[N][] (you can't omit the inner size, because the compiler needs it to find rows).
Generalization: for an n-dimensional array the address nests the same way — name + s_T*(i_1 + N_1*(i_2 + N_2*(…))) — and the outermost dimension is always the one you can leave unspecified.
Go deeper:
Row- and column-major order (Wikipedia) — row-major vs column-major storage order.