Pointers
The address-of operator you have been using with scanf, generalized into the feature that makes C usable
In a nutshell
A pointer is a variable that holds a memory address instead of a value. You have already used pointers, briefly, every time you wrote scanf("%d", &age). This topic generalizes that mechanic: any variable has an address (get it with &x), any address can be dereferenced (read or write the value with *p), and functions that take pointer parameters can modify a caller’s variables — the thing pass-by-value made impossible last week. Arrays decay to pointers in most expressions, which is why scanf("%s", name) works without &. Pointer arithmetic (p + n advances by n elements, not n bytes) is how you walk arrays without array subscripts.
Why it matters
You cannot write idiomatic C without pointers. Every non-trivial C function either takes or returns a pointer. Strings are pointers. File handles are pointers. Dynamically allocated memory is accessed through pointers. Linked lists, trees, and every data structure beyond a fixed-size array use pointers. And every exploitable memory bug in the history of C (use-after-free, double-free, buffer overflow, format string) is ultimately a pointer bug.
Key takeaways
&xgives the address ofx;*pdereferences (reads or writes the value atp).int *p = &x; *p = 42;setsxto42.- NULL is a pointer to no object. Check
if (p == NULL)before dereferencing anything that could be NULL. - A pointer has a type.
int *points to anint;char *points to achar. The type tells the compiler the size of the target and how arithmetic scales. - Pass-by-pointer lets a function modify the caller.
void swap(int *a, int *b)works;void swap(int a, int b)does not. - Array-to-pointer decay. In most expressions, an array name becomes a pointer to its first element.
arr[i]is exactly*(arr + i). - Pointer arithmetic scales by type size.
int *p; p + 3advances by3 * sizeof(int)bytes, not 3 bytes. - A pointer is always 8 bytes on a 64-bit machine, regardless of what it points to.
sizeof(int *)is 8 even thoughsizeof(int)is 4. - Double pointers (
int **) appear whenever a function needs to modify a pointer the caller owns (thinkargv,realloc-style resizing).
Lessons in this topic
| Lesson | What it covers |
|---|---|
| Pointer Basics | &, *, NULL, declaring a pointer, reading and writing through one |
| Pass-by-Pointer | Functions that modify the caller’s variables, including the mental model for scanf |
| Pointer Arithmetic & Array Duality | p + n, p - q, arr[i] as *(arr + i), walking an array without subscripts |
| Double Pointers | int **, when you need one, the argv pattern, modifying a caller’s pointer |
Practice and deep dives
Practice this topic: Pointers or Double Pointers drills, or browse the practice gallery.
For the machine-level picture (what &x resolves to on the stack, array-to-pointer decay explained, variadic promotions for printf), see the machine model deep dive.
What comes next
Dynamic Memory — pointers that come from the heap. malloc returns a pointer to memory you asked for. free returns it. Every pointer bug pattern you have read about (double-free, use-after-free, memory leak) lives here.