Nearby lessons
96 of 124C - Pointer to Array
A pointer to an array — int (*p)[5] — points at a whole array rather than a single element. Learn the parenthesised syntax, how arithmetic on it jumps a full array at a time, and why it is the correct type for a 2D array row.
The Parenthesised Declaration
The parentheses bind the * to the name before the [5] applies. Drop them and you get a completely different type:
Note the &
To get a pointer to the whole array you need &a, not a. The bare name a decays to int *:
Arithmetic Jumps a Whole Array
int * points to a 4-byte int, so +1 moves 4 bytes. An int (*)[5] points to a 20-byte array, so +1 moves 20 bytes — past the entire array.Three Ways to Reach an Element
All of these read the same value. p[0][i] is usually the clearest:
Why It Exists — 2D Array Rows
This is the real reason the type matters. For int m[3][4], the name m decays to a pointer to a row — that is, int (*)[4]:
Walking Rows by Incrementing
Because +1 advances a whole row, you can step through a matrix row by row:
The Correct Function Parameter
int m[][4] and int (*m)[4] are the same parameter type. This is why the column count is mandatory:
Why the Column Count Is Required
void f(int m[][], int rows) is a compile error, and for a good reason. To find m[2][1] the compiler computes base + 2 × columns + 1. Without the column count that arithmetic is impossible. The first dimension can be omitted because it never appears in the formula.Not the Same as int **
A common confusion. A real 2D array is one contiguous block; an int ** is an array of separate row pointers. They are not interchangeable:
int (*p)[4] | int **p | |
|---|---|---|
| Points to | An array of 4 ints | An int * |
| Memory | One contiguous block | Separate blocks per row |
Works with int m[3][4] | Yes | No |
Works with malloc'd rows | No | Yes |
p + 1 advances | 16 bytes | 8 bytes |
Common Mistakes
- Omitting the parentheses —
int *p[5]is an array of 5 pointers, not a pointer to an array. - Assigning
ainstead of&a— the bare name has typeint *. - Forgetting to dereference —
p[2]on anint (*p)[5]is a whole array, not an element. - Mixing up
int (*p)[4]andint **p— different memory layouts entirely. - Omitting the column count in a parameter — a compile error.
- Wrong column count —
int (*p)[3]aimed at anint m[2][4]reads the wrong offsets with no warning at use time.
int (*p)[5]: p — the parenthesis blocks going right, so go left: pointer — then right: to an array of 5 — then left: of int. For int *p[5]: p — go right: array of 5 — then left: of pointers to int.- int (*p)[5] points to an array of 5 ints — the parentheses are essential.
- p + 1 advances by a whole array, not one element.
- Access elements with (*p)[i] or p[0][i].
- For int m[3][4], the expression m has type int (*)[4].
- Without parentheses, int *p[5] is an array of pointers instead.