The declared slot holds length while a hash-derived region holds elements.
LET’S PICTURE IT
An index drawer stores a list count and points conceptually to a separately located shelf.
SEE IT FOR YOURSELF
Pack small values into Solidity storage slotsStep 1 / 4
In this simple default-layout example, two uint128 values come before one uint256. Each slot holds thirty-two bytes.
In this simple default-layout example, two uint128 values come before one uint256. Each slot holds thirty-two bytes.The first sixteen-byte value occupies the low-order half of slot zero. Low-order bytes are shown on the right.The second uint128 fits in the remaining sixteen bytes. Both values now share slot zero.C needs a complete thirty-two-byte slot, so it begins at slot one. Two packed small values plus C use two slots.
Animated local teaching model. No wallet, RPC or live blockchain data. Some labels and hashes are abbreviated for readability.
Locate the declared slot
For a dynamic storage array at slot p, that slot stores its length. The actual element region does not begin at p plus one.
Compute the element base
The element region starts at Keccak-256 of the thirty-two-byte encoding of p. For an array declared at slot three, hash that full encoded word.
Apply the element layout
For uint256 elements, index i is stored at base plus i, with slot arithmetic in the 256-bit space. Smaller element types may pack several values per word.
Distinguish nested arrays
A dynamic array of dynamic arrays needs a length and hash-derived region at each relevant level. Do not reuse a flat uint256-array formula for every nested type.
Inspect the layout
uint256[] items; // suppose declared slot p = 3
base = keccak256(ABI uint256(3))
base = 0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b
items[i] slot = base + i
The numeric slot assumption is explicit; inspect compiler output before applying it to a real contract.