Pointers & Arrays
Arrays and pointers are so closely intertwined in C that it is common to hear people say "an array is just a pointer" — which is close enough to be useful, but not quite true. This page works through exactly how the two relate, where they behave identically, and the important ways in which they are still different types.
Array-to-pointer decay
In most expressions, an array's name automatically "decays" into a pointer to its first element. This is why you can pass an array to a function that expects a pointer, and why arr and &arr[0] print the same address:
#include <stdio.h>
int main(void) {
int arr[3] = {7, 8, 9};
printf("arr = %p\n", (void *)arr);
printf("&arr[0] = %p\n", (void *)&arr[0]);
int *p = arr; // arr decays to &arr[0] here
printf("*p = %d\n", *p);
return 0;
}arr = 0x7ffe1c0a5a10 &arr[0] = 0x7ffe1c0a5a10 *p = 7
arr[i] is *(arr + i)
Array subscripting is not a special, separate mechanism in C — it is literally defined in terms of pointer arithmetic. The expression arr[i] means exactly *(arr + i): take the array (which decays to a pointer to its first element), advance it by i elements, and dereference. The two forms are fully interchangeable, and you can even see this in a surprising, rarely-used-in-practice fact: because addition is commutative, arr[i] and i[arr] mean the same thing.
#include <stdio.h>
int main(void) {
int arr[4] = {10, 20, 30, 40};
for (int i = 0; i < 4; i++) {
// These two expressions always produce the same value.
printf("arr[%d] = %d, *(arr + %d) = %d\n",
i, arr[i], i, *(arr + i));
}
// A curiosity that follows from the same rule (avoid in real code):
printf("2[arr] = %d\n", 2[arr]);
return 0;
}arr[0] = 10, *(arr + 0) = 10 arr[1] = 20, *(arr + 1) = 20 arr[2] = 30, *(arr + 2) = 30 arr[3] = 40, *(arr + 3) = 40 2[arr] = 30
Where arrays and pointers genuinely differ
Despite decaying to a pointer in expressions, an array variable is not itself a pointer variable, and the difference shows up in two places: sizeof and reassignment.
Aspect | Array | Pointer |
|---|---|---|
| Gives the size of the whole array in bytes ( | Gives the size of the pointer variable itself (typically 8 bytes on a 64-bit system), regardless of what it points to |
Reassignment | The array name always refers to the same block of memory — it cannot be made to point elsewhere | A pointer variable can be reassigned to point at a different location at any time |
Storage | The elements themselves are stored in the array's own memory (stack, static, or as part of a struct) | The pointer is a separate variable that merely stores an address — the pointed-to data lives elsewhere |
#include <stdio.h>
int main(void) {
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;
printf("sizeof(arr) = %zu bytes\n", sizeof(arr)); // whole array
printf("sizeof(p) = %zu bytes\n", sizeof(p)); // just the pointer
int other[3] = {100, 200, 300};
p = other; // fine: p can point somewhere else
// arr = other; // ERROR: arrays are not assignable
return 0;
}sizeof(arr) = 20 bytes sizeof(p) = 8 bytes
An array name decays to a pointer to its first element in almost every expression context.
arr[i]and*(arr + i)are defined to mean exactly the same thing.sizeofon an array gives the whole array's byte size;sizeofon a pointer gives only the pointer's own size.An array variable is a fixed block of memory and cannot be reassigned; a pointer variable can be repointed freely.