Ch5.3: Dereferencing
Overview
A pointer stores an address. Dereferencing means: use the pointer to access the object at that address.
In this chapter, you will learn:
- how to dereference a pointer using
*p - how to read and write through a pointer
- how to dereference pointer-to-pointer
- why dereferencing invalid pointers is a serious memory‑safety vulnerability
- how to detect invalid dereferences using sanitizers
- how to visualize dereferencing with pseudo‑graphs
1. What does dereferencing mean?
If a pointer stores an address, dereferencing means “go to that address and access the object stored there”.
value:
Address: 3000
Memory: [ 42 ]
p:
Address: 4000
Memory: [ 3000 ] ← p stores address of value
#include <memory>
int value{42};
int *p = ::std::addressof(value);
int x = *p; // x becomes 42
2. Reading through a pointer
Dereferencing lets you read the value stored at the pointer’s address.
int n{100};
int *p = ::std::addressof(n);
int copy = *p; // copy becomes 100
3. Writing through a pointer
Dereferencing also lets you modify the object the pointer refers to.
int n{5};
int *p = ::std::addressof(n);
*p = 20; // changes n to 20
4. Dereferencing pointer-to-pointer
If you have a pointer-to-pointer, you can dereference it twice.
int value{7};
int *p = ::std::addressof(value);
int **pp = ::std::addressof(p);
int x = **pp; // x becomes 7
value:
Address: 3000
Memory: [ 7 ]
p:
Address: 4000
Memory: [ 3000 ]
pp:
Address: 5000
Memory: [ 4000 ]
**pp → *p → value → 7
5. Dereferencing nullptr is undefined behavior
A pointer must point to a valid object before you dereference it.
Dereferencing nullptr is undefined behavior.
int *p = nullptr;
// *p = 10; // undefined behavior — never do this
6. Dereferencing invalid pointers is a serious memory‑safety vulnerability
Dereferencing an invalid pointer is not just a bug — it is a serious memory‑safety vulnerability. It can lead to:
- memory corruption
- data leaks
- crashes
- security exploits
A pointer is invalid if it is:
- null (
nullptr) - uninitialized
- dangling (object no longer exists)
- forged (manually assigned an arbitrary number)
- out of bounds
Examples
// 1. Null pointer
int *p = nullptr;
// *p = 10; // undefined behavior
// 2. Uninitialized pointer
int *q;
// *q = 10; // undefined behavior
// 3. Dangling pointer
int *r = nullptr;
{
int x{5};
r = ::std::addressof(x);
} // x is destroyed here
// *r = 10; // undefined behavior
// 4. Forged pointer
int *s = reinterpret_cast(12345);
// *s = 10; // undefined behavior
Rule: Only dereference a pointer if you are absolutely certain it points to a valid, alive object.
7. Use sanitizers to detect invalid dereferences
Modern compilers provide tools that detect invalid pointer dereferences at runtime. You should always enable them during development.
AddressSanitizer
-fsanitize=address
Detects:
- null dereferences
- use‑after‑free
- out‑of‑bounds accesses
- stack and heap buffer overflows
Memory Tagging (WebAssembly)
-fsanitize=memtag
Detects:
- dangling pointer dereferences
- incorrect pointer arithmetic
- invalid memory accesses
These tools make pointer bugs easier to find and fix.
8. Printing dereferenced values
You can print the value obtained by dereferencing just like any other value.
#include <fast_io.h>
#include <memory>
int n{55};
int *p = ::std::addressof(n);
println(*p); // prints 55
Key takeaways
*pmeans “the object pointed to byp”.- You can read and write through a pointer.
- Pointer-to-pointer types can be dereferenced multiple times.
- Dereferencing nullptr is undefined behavior.
- Dereferencing uninitialized, dangling, forged, or out‑of‑bounds pointers is undefined behavior.
- Invalid dereferences are serious memory‑safety vulnerabilities.
- Use
-fsanitize=addressor-fsanitize=memtagto detect invalid dereferences.