Pointers and References, Explained
What a pointer actually is, how references differ, why they power linked lists and trees, and how higher-level languages hide raw addresses behind reference semantics.
Memory is just a long row of numbered boxes. A pointer is a box whose contents are the number of another box. Once you internalize that one sentence, half the mystery of C, linked lists, and “why did my object change?” disappears.
A Pointer Holds an Address
Every byte in a running program lives at a numeric address. A pointer is an ordinary variable whose value happens to be one of those addresses. When you have a pointer, you can dereference it — follow the address to read or write the value it refers to.
int x = 42;int *p = &x; // p holds the address of xprintf("%d\n", *p); // dereference: prints 42*p = 99; // write through the pointerprintf("%d\n", x); // x is now 99The & operator takes the address of a variable; the * operator dereferences a pointer. Because p knows where x lives, writing through p changes x itself. That indirection is the whole point: two parts of a program can hold the same address and therefore see the same data. Pass a pointer into a function and the function can modify the caller’s variable, not a copy.
This is also why pointers enable dynamic data structures. A linked list is just nodes where each node holds a value plus a pointer to the next node; a binary tree node holds pointers to its children. The nodes can sit anywhere in memory — the pointers stitch them together. You can grow and shrink these structures at runtime by allocating new nodes and rewiring pointers, something a fixed-size array cannot do.
References Are Safer Aliases
A reference is a name that refers to an existing variable — an alias. In C++, once a reference is bound to a variable, using the reference is using that variable, with no * needed:
int x = 42;int &r = x; // r is another name for xr = 99; // x is now 99A C++ reference is, under the hood, much like a pointer, but the language adds guardrails: it must be initialized when declared, it cannot be reseated to refer to something else, and it cannot (in well-formed code) be null. That makes references convenient for passing arguments without copying while avoiding the sharp edges of raw pointer arithmetic.
The word “reference” gets reused with different meanings across languages. In Java and Python, you never touch raw addresses at all. Variables that hold objects hold references to those objects, and the runtime manages the actual memory and garbage collection. Go sits in between: it has explicit pointers (*T, &x) but no pointer arithmetic, and the garbage collector keeps them safe. Python’s model is sometimes called “names bound to objects”: a name is a label attached to an object, and assignment rebinds the label rather than copying the object.
Null and the Billion-Dollar Mistake
A pointer can point at nothing — represented as null (NULL, nullptr, nil, or None depending on the language). Dereferencing a null pointer is a classic crash: a segmentation fault in C, a NullPointerException in Java, an AttributeError on None in Python.
Tony Hoare, who introduced the null reference in ALGOL W in 1965, later called it his “billion-dollar mistake,” because of the countless crashes and vulnerabilities it has caused over the decades. The lesson stuck. Modern languages fight back with non-nullable types, optionals, and the borrow checker: Rust has no null at all, encoding “maybe absent” in its Option type; Kotlin and Swift distinguish nullable from non-nullable types in the type system; Go’s nil and modern C++ smart pointers narrow the blast radius. The underlying idea is to make “this might be absent” something the compiler can check, rather than a landmine you discover at runtime.
FAQ
Understanding pointers is less about syntax than about the mental model: a value can either be the data or point to the data, and indirection is what lets independent pieces of code agree on the same object.
FAQ
Is a reference just a pointer with nicer syntax?+
Why do linked lists and trees need pointers?+
If Python hides pointers, why does mutating a passed list affect the caller?+
Related reading
2026-06-04
ACID vs BASE: What Database Guarantees Actually Promise
ACID and BASE describe two ends of a tradeoff between strict correctness and scalable availability. Learn what each guarantee means, when each fits, and why most modern databases sit somewhere in between.
2026-06-04
Big-Endian vs Little-Endian
Byte order explained: how big-endian and little-endian lay out multi-byte numbers in memory, why network protocols pick one, and when the difference actually bites you.
2026-06-04
Big-O Notation in Plain English
Big-O describes how an algorithm's runtime or memory grows as input grows. Learn the common classes — O(1), O(log n), O(n), O(n log n), O(n^2), O(2^n) — with plain examples.
2026-06-04
CORS in Plain English: Why the Browser Blocks Your Fetch
A clear walkthrough of CORS and the same-origin policy — what an origin is, why your fetch fails, how servers opt in, and the big misconception about who CORS actually protects.
2026-06-04
Environment Variables and PATH, Explained
What environment variables actually are, why they hold config and secrets, and how PATH decides which binary runs when you type a command.
Get the best tools, weekly
One email every Friday. No spam, unsubscribe anytime.