C Programming: Understanding Pointers Once and For All
Introduction
Pointers break a lot of new programmers. They broke me, too — for a while. I was writing JavaScript and Python before I learned C, and the jump required rewiring some fundamental assumptions about how variables and memory work.
The thing is, pointers aren't complicated once the mental model is right. They're just addresses — numbers that tell you where to find data in memory. Every confusion about pointers comes from muddling the address (the pointer) with the thing it points to (the value). Once you keep that distinction clear and automatic, everything else follows.
This post builds the mental model from first principles, then applies it to the patterns you'll encounter in real C code.
Core Concepts
Memory as a Long Array
Visualise RAM as a giant array of bytes, each with a numbered address starting at 0. When you declare a variable, the system allocates some of those bytes and gives you a name for that location:
int x = 42;This sets aside 4 bytes (on most systems), puts the value 42 in those bytes, and gives you the name x to refer to them. The variable x doesn't contain the address — it is at an address. You can find out that address using the address-of operator &:
printf("Value of x: %d
", x); // 42
printf("Address of x: %p
", (void*)&x); // 0x7ffc1234abcd (example)What a Pointer Is
A pointer is a variable whose value is a memory address. That's the entire definition.
int x = 42;
int *p = &x; // p stores the address of xNow p holds the address of x. To get the value at that address — called dereferencing — you use *:
printf("%d
", *p); // 42 — the value at the address p holdsThree things to keep clear:
| Expression | Meaning |
|---|---|
| x | The value stored at x's address (42) |
| &x | The address of x (e.g., 0x7ffc1234abcd) |
| p | The value of the pointer variable (same address) |
| *p | The value stored at the address p holds (42) |
p and &x are the same number. *p and x are the same number.
Pointer Declarations
The * in a declaration means "this variable is a pointer to [type]":
int *p; // pointer to int
char *s; // pointer to char
float *f; // pointer to float
int **pp; // pointer to a pointer to intA common source of confusion: the * in int *p belongs to the variable name, not the type. This matters when declaring multiple pointers:
int *a, *b; // Both are pointers — correct
int* a, b; // a is a pointer, b is a plain int — common mistakeWhy Pointer Size Is Always the Same
Regardless of what type a pointer points to, the pointer itself is always the same size — typically 8 bytes on a 64-bit system. That makes sense: a pointer is just a memory address, and the size of a memory address is determined by the architecture, not by what lives at that address.
printf("%zu
", sizeof(int*)); // 8 (on 64-bit)
printf("%zu
", sizeof(char*)); // 8Pointer Arithmetic
Pointers can be incremented or decremented to point to adjacent memory locations:
int x = 10;
int *p = &x;
p++;
printf("%d
", *p);Each increment or decrement moves the pointer by the size of the type it points to.
Dynamic Memory
Pointers can be used to allocate memory dynamically:
int *p = malloc(sizeof(int));
*p = 42;
printf("%d
", *p);Memory allocated with malloc must be freed with free.
Function Pointers
Pointers can be used to call functions:
int (*f)(int, int);
f = &add;
printf("%d
", f(3, 4));Function pointers are useful for callbacks and function tables.
Common Pitfalls
Common mistakes include:
- Confusing pointers with values
- Using pointers without proper initialization
- Not freeing memory allocated with
malloc
Conclusion
Pointers are a fundamental concept in C programming. Once you understand the mental model, they become much easier to use.
Further Reading
- Learn C: Pointers Tutorial
- Understanding Pointers in C