C++ by Example
C++ by Example

Pointers

2 min read

Pointers

A pointer holds the memory address of another variable. Pointers are central to C++ — they underpin arrays, dynamic allocation, polymorphism, and data structures. They are also a common source of bugs. Modern C++ reduces direct pointer use through smart pointers and references, but understanding raw pointers is still essential.

Declaring and using pointers

#include <iostream>

int main() {
    int x = 42;
    int* p = &x;   // p holds the address of x

    std::cout << x  << "\n";    // 42    — the value
    std::cout << p  << "\n";    // 0x... — the address
    std::cout << *p << "\n";    // 42    — dereference: value at address

    *p = 100;                   // modify x through p
    std::cout << x << "\n";     // 100
}

&x is the address-of operator. *p is the dereference operator — it reads or writes the value at the address stored in p.

nullptr

Use nullptr for a pointer that points to nothing:

int* p = nullptr;

if (p != nullptr) {
    std::cout << *p << "\n";
} else {
    std::cout << "null pointer\n";
}

Dereferencing nullptr is undefined behavior — it typically crashes the program. Always check before dereferencing a pointer that might be null.

Pointer arithmetic

Adding an integer to a pointer advances it by that many elements (not bytes):

#include <iostream>

int main() {
    int arr[5] = {10, 20, 30, 40, 50};
    int* p = arr;   // points to arr[0]

    std::cout << *p     << "\n";   // 10
    std::cout << *(p+1) << "\n";   // 20
    std::cout << *(p+4) << "\n";   // 50

    p++;
    std::cout << *p << "\n";       // 20
}

Array indexing arr[i] is exactly *(arr + i).

Pointers to pointers

int x = 5;
int* p  = &x;
int** pp = &p;   // pointer to pointer

std::cout << **pp << "\n";   // 5

Double pointers appear in C APIs that need to return a pointer through a parameter.

const and pointers

const can apply to the pointer, the pointed-to value, or both:

int x = 10, y = 20;

const int* p1 = &x;    // pointer to const int: cannot modify *p1
p1 = &y;               // can reassign the pointer itself

int* const p2 = &x;    // const pointer to int: cannot reassign p2
*p2 = 99;              // can modify the value

const int* const p3 = &x;  // neither the pointer nor the value can change

The rule: read the declaration right-to-left. const int* — "pointer to const int."

void*

A void* pointer holds an address with no type information. It can point to anything but cannot be dereferenced without casting:

void* raw = malloc(64);
int* ip = static_cast<int*>(raw);
*ip = 42;
free(raw);

void* is common in C APIs but rare in modern C++. Smart pointers and templates eliminate most of its traditional uses.

Pointer vs. reference

Feature Pointer Reference
Can be null Yes No
Can be reseated Yes No
Syntax at call site f(&x) f(x)
Arithmetic Yes No

Use references when the value is always present and you do not need to reseat; use pointers when null is a valid state or when you need dynamic dispatch over ownership.

C++ by Example
C++ by Example

Learn modern C++ through working code. Each chapter introduces one concept — variables, functions, classes, templates, smart pointers, concurrency — with a clear example, a line-by-line explanation, and notes on how it applies in real programs.

View book →