Reading — step 1 of 7
Learn
A pointer holds the memory address of another value. C++'s pointers are powerful but unforgiving — understanding them is the line between working code and segfaults.
The basic mechanics
int x = 42;
int* p = &x; // p stores the address of x
*p = 100; // dereference and assign — x is now 100
std::cout << x; // 100
std::cout << p; // an address like 0x7fff...
std::cout << *p; // 100
&— the address-of operator.&xgives you a pointer to x.*(in declarations) — "this is a pointer to ..."*(in expressions) — dereference: "the value the pointer points to."
Declaration vs use looks similar but means different things — read carefully.
Pointer arithmetic
Pointers can be incremented and compared:
int arr[5] = {10, 20, 30, 40, 50};
int* p = arr; // points to arr[0]
p++; // now points to arr[1]
std::cout << *p; // 20
std::cout << *(p + 2); // 40
p + 1 advances by sizeof(int) bytes, not 1. The compiler does the math based on the pointer's type. This is why pointer arithmetic on void* is illegal — the compiler doesn't know the element size.
Null pointers
A pointer that points nowhere:
int* p = nullptr;
if (p != nullptr) { /* safe to dereference */ }
if (p) { /* same — pointer in boolean context */ }
// Dereferencing nullptr is undefined behavior:
// *p = 5; // CRASH — segfault
Always use nullptr (C++11+), not NULL (a macro for 0) or 0. nullptr is its own type and won't cause overload-resolution surprises.
Const correctness with pointers
Four combinations:
int x = 5;
const int* p1 = &x; // pointer to const int — can't modify *p1
int* const p2 = &x; // const pointer — can't reassign p2 (but can modify *p2)
const int* const p3 = &x; // both const
int* p4 = &x; // mutable pointer to mutable int
Read RIGHT to LEFT: const int* = "pointer to int that's const." Use const to document intent — read-only data should be const T*.
Pointers vs References
int x = 10;
int& ref = x; // reference — alias for x; can't be null, can't be rebound
int* ptr = &x; // pointer — can be null, can be reassigned
ref = 20; // changes x to 20
*ptr = 30; // changes x to 30
// References are simpler — prefer them when you don't need null or reassignment.
Use references for function parameters and return types when you don't need the pointer's flexibility. Pointers when:
- The value can be missing (nullptr)
- You need to point at different objects over time
- You're managing dynamic memory (next lesson)
- Interop with C APIs
Dangling pointers — the classic bug
int* dangle() {
int x = 42;
return &x; // ✗ x dies when dangle() returns; pointer is dangling
}
int* p = dangle();
std::cout << *p; // undefined behavior — could be anything
Returning a pointer to a local is one of C++'s most-classic bugs. The compiler may warn; if not, valgrind/asan catches it at runtime.
Common mistakes
- Dereferencing nullptr — segfault. Always check before dereferencing if it could be null.
- Pointer arithmetic past array bounds — undefined behavior. Stay within [arr, arr + size).
- Mixing up declaration and expression
*—int* p; *p = 5;are very different uses. - Returning pointers to locals — dangling. Return by value or use heap allocation.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…