Skip to content
Pointers in Depth
step 1/7

Reading — step 1 of 7

Learn

~3 min readPointers and Memory

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. &x gives 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…