CPointers & Arrays

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:

C
#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.

C
#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
A neat fact, not a style guide
`2[arr]` working is a fun way to internalize that `arr[i]` really is just `*(arr + i)` in disguise, but you should always write `arr[2]` in real code — reversing the order communicates nothing and only confuses readers.
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

sizeof

Gives the size of the whole array in bytes (element size × element count)

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

C
#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
A frequent sizeof mistake
`sizeof` only reports the full array size when applied directly to an array variable that is still in scope as an array. The moment that array is passed to a function, its parameter decays to a plain pointer, and `sizeof` on that parameter reports the pointer's size, not the original array's — a classic bug covered in depth in Arrays & Functions.
  • 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.

  • sizeof on an array gives the whole array's byte size; sizeof on 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.