Pointers and References Quick Reference
C++ pointers and references cheatsheet — raw pointers, references, pointer arithmetic, const correctness, nullptr, and smart pointer overview.
Raw Pointers
cpp
int x = 42;
int* p = &x; // pointer to int
*p = 99; // dereference: x is now 99
int** pp = &p; // pointer to pointer
// Null checks
int* q = nullptr; // null pointer (C++11)
if (p != nullptr) { }
if (p) { } // same
if (!q) { } // null check
// Pointer arithmetic (only valid within arrays)
int arr[5] = {10, 20, 30, 40, 50};
int* it = arr; // points to arr[0]
*(it + 2); // arr[2] = 30
it++; // it now points to arr[1]
ptrdiff_t diff = it - arr; // 1const and Pointers
cpp
int val = 42;
int* p1 = &val; // mutable pointer, mutable pointee
const int* p2 = &val; // mutable pointer, const pointee (can't write *p2)
int* const p3 = &val; // const pointer, mutable pointee (can't rebind p3)
const int* const p4 = &val; // const pointer, const pointee
*p2 = 0; // error: read-only through p2
p2 = nullptr; // OK: pointer itself is mutable
*p3 = 0; // OK: pointee is mutable
p3 = nullptr; // error: pointer is const
// Mnemonic: read right-to-left
// const int* → "pointer to const int"
// int* const → "const pointer to int"References
cpp
int x = 5;
int& r = x; // reference: alias for x — must bind at init
r = 10; // x is now 10
&r == &x; // true — same address
// No null references, no rebinding
// int& r2; // error: must initialize
// r = y; // assigns to x, doesn't rebind r
// const reference — binds to rvalues and temporaries
const int& cr = 42; // OK: lifetime extended
cr = 0; // error
// rvalue reference
int&& rr = 42; // binds rvalue
int&& rr2 = std::move(x); // binds moved xPointer vs Reference
| Pointer | Reference | |
|---|---|---|
| Nullable | Yes (nullptr) | No |
| Rebindable | Yes | No |
| Syntax | *p, p->m | r, r.m |
| Arithmetic | Yes | No |
| Arrays | Yes | No (use span) |
| Optional param | Yes | No (use optional) |
| Prefer when | Nullable/rebind needed | Non-nullable alias |
Function Pointers
cpp
int add(int a, int b) { return a + b; }
// Declare
int (*fp)(int, int) = add;
fp(3, 4); // 7
// Using alias (clearer)
using BinOp = int(*)(int, int);
BinOp op = add;
// Array of function pointers
BinOp ops[] = {add, [](int a, int b){ return a - b; }};
ops[0](3, 4); // 7
ops[1](3, 4); // -1Pointer to Array and Array of Pointers
cpp
int arr[5];
int* p = arr; // pointer to first element (decays from array)
int (*pa)[5] = &arr; // pointer to array of 5 ints
(*pa)[2] = 99; // same as arr[2] = 99
// Array of pointers
int a = 1, b = 2, c = 3;
int* ptrs[3] = {&a, &b, &c};
*ptrs[1] = 99; // b = 99new / delete (avoid in modern C++)
cpp
// Prefer make_unique/make_shared
int* p = new int{42};
delete p;
int* arr = new int[10]{};
delete[] arr; // MUST use delete[] for arrays
// Placement new
alignas(int) std::byte buf[sizeof(int)];
int* p2 = ::new(buf) int{7};
p2->~int(); // must destroy explicitlySmart Pointers (Prefer These)
cpp
#include <memory>
// unique_ptr — exclusive ownership, zero overhead
auto up = std::make_unique<Widget>(args...);
up->do_work();
// freed when up goes out of scope
// shared_ptr — shared ownership, ref-counted
auto sp1 = std::make_shared<Widget>();
auto sp2 = sp1; // ref count = 2
// weak_ptr — non-owning observer
std::weak_ptr<Widget> wp = sp1;
if (auto locked = wp.lock()) {
locked->do_work();
}
// unique_ptr for arrays
auto arr = std::make_unique<int[]>(10);
arr[3] = 42;void* and Casts
cpp
void* vp = &x; // holds any pointer
int* ip = static_cast<int*>(vp); // must cast back to use
// reinterpret_cast — low-level type pun (use std::bit_cast instead in C++20)
float f = 3.14f;
int bits = std::bit_cast<int>(f); // preferred (C++20)
// C-style cast — avoid
int* p3 = (int*)vp; // avoid: doesn't check safetyCommon Mistakes
cpp
// 1. Dangling pointer
int* bad_ptr;
{
int local = 5;
bad_ptr = &local;
}
*bad_ptr; // UB: local destroyed
// 2. Uninitialized pointer
int* p; // indeterminate value — don't read
*p = 0; // UB
// 3. Off-by-one in pointer arithmetic
int arr[5];
int* end = arr + 5; // OK: one past end is valid (don't dereference)
*end = 0; // UB: one past end
// 4. Signed/unsigned mismatch in pointer arithmetic
size_t n = 5;
ptrdiff_t diff = end - arr; // ptrdiff_t, not size_t
// 5. delete non-heap pointer
int stack_var = 5;
int* p2 = &stack_var;
delete p2; // UB: not heap allocated