Solution
The correct answer is *(*(*(ar + m) + n) + o)
Key Ideas
- In C, the subscript rule is:
a[i] ≡ * (a + i). This is true for every dimension.
- When an array name appears in an expression (not as
sizeof or unary &), it decays to a pointer to its first element.
- For a 3-D array
int ar[X][Y][Z];, the “first element” is the first 2-D block ar[0], whose type is int [Y][Z]. After decay, ar has type int (* )[Y][Z] (pointer to a [Y][Z] array).
Step-by-step expansion of ar[m][n][o]
ar[m] Use the rule once: ar[m] ≡ * (ar + m). Meaning: move m blocks of size Y×Z elements to reach the 2-D block starting at ar[m].
ar[m][n] Apply the rule inside that block: ar[m][n] ≡ * ( *(ar + m) + n ). Here, *(ar + m) has type int [Y][Z] and decays to pointer to its first row, so + n steps n rows, each of length Z.
ar[m][n][o] Apply the rule again on the 1-D row: ar[m][n][o] ≡ * ( *(*(ar + m) + n) + o ). Now *(*(ar + m) + n) has type int [Z] and decays to int*, so + o steps to the o-th element, and final * fetches the value.
Final pointer form
*(*(*(ar + m) + n) + o)
Type trail (to see why the dereferences are needed)
ar : int (*)[Y][Z] (pointer to 2-D block)
ar + m : int (*)[Y][Z]
*(ar + m) : int [Y][Z] (the m-th 2-D block)
*(ar + m) (decays) : pointer to first row → int (*)[Z]
*(ar + m) + n : int (*)[Z] (pointer to n-th row)
*(*(ar + m) + n) : int [Z] (the n-th row)
*(*(ar + m) + n) (decays) : int * (pointer to first element in row)
*(*(ar + m) + n) + o : int * (pointer to o-th element)
*(*(*(ar + m) + n) + o) : int (the element value)
How pointer arithmetic scales correctly
ar + m jumps by m × Y × Z integers (size of one 2-D block).
*(ar + m) + n then jumps by n × Z integers (size of one row) inside that block.
... + o finally moves by o integers within the row.
Common mistakes (why the other patterns are wrong)
- Missing a dereference: expressions like
(*(*(ar + m) + n) + o) stop at a pointer and do not fetch the element.
- Wrong grouping/order: e.g.,
*(*(ar + m + n) + o) mixes dimensions and does not move by row sizes correctly.
- Too few
*: you need three dereferences for three dimensions (block → row → element).
Mini numeric example
int ar[2][3][4]; // X=2, Y=3, Z=4
// Address math (assuming int is 4 bytes, just for intuition):
// base(ar) + (m * 3 * 4 + n * 4 + o) * sizeof(int)
For m=1, n=2, o=3 the offset in elements is 1*12 + 2*4 + 3 = 12 + 8 + 3 = 23, which is exactly what *(*(*(ar + 1) + 2) + 3) reaches by three scaled pointer steps.