Card 02/ 09
Compute an Element's Address in One and Two Dimensions
Base address plus index times cell size, and for a grid, row times width first.
Every element of an array lives at an address computed from its index, and a grid stored in one array adds one step to that computation. This card covers the one-dimensional formula, the row-major layout that stores a grid row by row, and the two-dimensional formula that follows from it.
The goal is to find the element at a given row and column of a grid kept in one flat array. You need multiplication, and the fact that an array's cells are the same size and sit side by side.
From a grid cell to an index, and from an index to an address
Multiply the index by the cell size
In one dimension, cell i starts at base + i × size, where base is the address of cell 0 and size is the number of bytes in a cell. For prices stored as eight-byte numbers from address 5000:
| Index | Arithmetic | Address |
|---|---|---|
| 0 | 5000 + 0 × 8 | 5000 |
| 1 | 5000 + 1 × 8 | 5008 |
| 2 | 5000 + 2 × 8 | 5016 |
| 9 | 5000 + 9 × 8 | 5072 |
Lay the grid out row by row
Memory has one dimension, so a grid of three rows and four columns has to be put in some order. Row-major order stores row 0 first, then row 1, then row 2, so each row fills cols consecutive cells. Python's lists of lists and Java's int[][] keep each row as an array of its own instead; a flat array is what you build when the whole grid should sit in one block, as an image's pixels usually do.
| Row | Column 0 | Column 1 | Column 2 | Column 3 |
|---|---|---|---|---|
| Row 0 | A (0) | B (1) | C (2) | D (3) |
| Row 1 | E (4) | F (5) | G (6) | H (7) |
| Row 2 | I (8) | J (9) | K (10) | L (11) |
Skip whole rows, then count along
To reach row r, skip r full rows of cols cells each, then move c cells along: index = r × cols + c. The multiplier is the number of columns, because a row is as long as the grid is wide.
Applied to the grid above, the formula picks each letter out of the flat array.
Before the trace: at which index of the flat array does grid[1][2], the letter G, sit?
At 6: skip one row of four cells, then move two along.
The trace reads three cells through the flat array; index marks r × cols + c.
Inputa grid of three rows and four columns, stored row by row as A to L
Read grid[0][0]
- Aindex
- B
- C
- D
- E
- F
- G
- H
- I
- J
- K
- L
0 × 4 + 0 = 0: A, the first cell of row 0.
Read grid[1][2]
- A
- B
- C
- D
- E
- F
- Gindex
- H
- I
- J
- K
- L
1 × 4 + 2 = 6: skip the four cells of row 0, then two more, to G.
Read grid[2][3]
- A
- B
- C
- D
- E
- F
- G
- H
- I
- J
- K
- Lindex
2 × 4 + 3 = 11: skip two rows of four, then three more, to L.
ResultCell (r, c) sits at index r × cols + c, here r × 4 + c.
The address then follows from the first step: base + (r × cols + c) × size. With four-byte cells from address 1000, G sits at 1000 + 6 × 4 = 1024.
To know the formula is right, a check compares each cell of the grid with the one the formula picks out of the flat array.
rows = 3
cols = 4
grid: list[list[str]] = [
["A", "B", "C", "D"],
["E", "F", "G", "H"],
["I", "J", "K", "L"],
]
flat: list[str] = [cell for row in grid for cell in row]
def flat_index(r: int, c: int) -> int:
return r * cols + c
mismatches = 0
for r in range(rows):
for c in range(cols):
if flat[flat_index(r, c)] != grid[r][c]:
mismatches += 1
print(" ".join(flat))
print(f"{rows * cols} cells checked, {mismatches} mismatches")
print(f"grid[1][2] = {grid[1][2]}, flat[{flat_index(1, 2)}] = {flat[flat_index(1, 2)]}")A B C D E F G H I J K L
12 cells checked, 0 mismatches
grid[1][2] = G, flat[6] = GThe formula is right when it agrees with the layout for every cell, not only the one you tried, and the check found no mismatch in 12. A wrong multiplier usually fails at the first cell of row 1: r × rows + c sends grid[1][0] to index 3, which holds D rather than E.
← → move through sections and cards