Thanks to the link provided by @tesseract in the comments: Expert C Programming: Deep C Secrets (page 96), I came up with a simple answer (a simple dumb down version of the explanation in the book; for a full academic answer read the book):
- when declared
int a[2]
:- the compiler has for
a
an address where this variable is stored. This address is also the address of the array since the type of the variable is array. - Accessing
a[1]
means:- retrieving that address,
- adding the offset and
- accessing the memory at this computed new address.
- the compiler has for
- when declared
int *b
:- the compiler also has an address for
b
but this is the address of the pointer variable, not the array. - So accessing
b[1]
means:- retrieving that address,
- accessing that location to get the value of
b
, i.e. the address of the array - adding an offset to this address and then
- accessing the final memory location.
- the compiler also has an address for