Pointer arithmetic in C lets you do math on pointers: adding integers, subtracting pointers, indexing into arrays without explicit [i] syntax. The catch is that arithmetic is scaled by the size of the pointer’s referenced type, so ptr + 1 advances by sizeof(*ptr) bytes, not one byte. This is how you work with C arrays, traverse linked structures, and build low-level data structures.

Why pointers exist

Pointers solve the “modify the caller’s value” problem. The naïve swap function:

void swap(int a, int b){
    int tmp = a;
    a = b;
    b = tmp;
}
int x = 1, y = 2;
swap(x, y);    // x and y unchanged

This swaps copies of a and b inside the function. C is call-by-value — the caller’s x and y are never touched. The fix is to pass pointers:

void swap(int *a, int *b){
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
int x = 1, y = 2;
swap(&x, &y);  // now x and y are swapped

Pointer values are also copied, but those copies still point at the original x and y. Dereferencing them (*a) reads or writes the original variables.

Operators

Three operators control pointers:

  • & (address-of) — gives the memory address of a variable. int *p = &total; makes p point to total.
  • * (dereference) — given a pointer, get or set the value at that address. *p = 12; writes 12 into the variable p points at.
  • -> — shortcut for “dereference the pointer, then access a field.” p->field is the same as (*p).field.

Example:

int total = 5;
int *nptr = &total;     // nptr points to total
*nptr = 12;             // total is now 12

Pointer indexing

For an array, the array name decays to a pointer to its first element:

int numbers[4];
int *nptr = numbers;    // no & needed; numbers is already a pointer

You can add or subtract integers from the pointer:

*(nptr + 2) = 10;       // sets numbers[2] to 10

The arithmetic is scaled by the size of the pointed-to type. If nptr is int * (and int is 4 bytes), then nptr + 2 advances 8 bytes — to the third element, not the third byte.

This is why numbers[i] and *(numbers + i) are equivalent in C — they both compute “address of element of numbers.”

What pointer arithmetic doesn’t do

  • Multiplication and division of pointers — not legal.
  • Adding two pointers — not legal (what would the result mean?).
  • Pointer arithmetic across array boundaries — legal up to one-past-the-end, undefined beyond. The standard explicitly allows &array[5] on a 5-element array; that’s the canonical “end” pointer used in for (p = array; p != array+5; p++) loops. What’s undefined is dereferencing it (*p at end) or going further (array+6).

Where this shows up in data structures

Linked structures (linked lists, trees, graphs) live in scattered memory connected by pointers. Working with them means dereferencing chains of pointers, allocating new nodes via malloc, and tracking what’s a pointer vs. a value. Array-based structures (dynamic arrays, heaps) use pointer arithmetic to move data around.

For C structs, see C struct. For runtime memory allocation, see Dynamic memory allocation.