Pointer arithmetic in C lets you do math on pointers — adding integers, subtracting pointers, indexing into arrays without explicit [i] syntax. The catch: 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 fundamental to working with C arrays, traversing linked structures, and implementing 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 unchangedThis 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 swappedPointer 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;makesppoint tototal.*(dereference) — given a pointer, get or set the value at that address.*p = 12;writes 12 into the variableppoints at.->— shortcut for “dereference the pointer and access a field.”p->fieldis the same as(*p).field. Saves typing when accessing struct fields through pointers.
Example:
int total = 5;
int *nptr = &total; // nptr points to total
*nptr = 12; // total is now 12Pointer 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 pointerYou can add or subtract integers from the pointer:
*(nptr + 2) = 10; // sets numbers[2] to 10The 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 infor (p = array; p != array+5; p++)loops. What’s undefined is dereferencing it (*pat end) or going further (array+6).
Why this matters for data structures
Linked structures (linked lists, trees, graphs) live in scattered memory locations connected by pointers. Manipulating them means dereferencing chains of pointers, allocating new nodes via malloc, and being careful about what’s a pointer and what’s a value. Pointer arithmetic is also how array-based structures (dynamic arrays, heaps) move data around efficiently.
For C structs (the building blocks of complex data structures), see C struct. For runtime memory allocation, see Dynamic memory allocation.