C++ Pointers & References
Raw Pointers
Address-of and dereference
int x = 42;
int* ptr = &x; // ptr holds the address of x
std::cout << ptr; // 0x7ffd1234abcd (address)
std::cout << *ptr; // 42 (dereferenced value)
*ptr = 100;
std::cout << x; // 100 — x was modified through ptr
&x gets the address. *ptr dereferences to get the value. Pointers can be null, reassigned, and used for pointer arithmetic.
Null Pointers
nullptr replaces NULL in modern C++
int* ptr = nullptr; // modern C++ — type-safe null
if (ptr != nullptr) {
std::cout << *ptr; // safe — only dereference if not null
}
// Common pattern: check before use
void process(int* data) {
if (!data) return; // guard clause
std::cout << *data << std::endl;
}
Dereferencing a null pointer is undefined behavior. Always check before dereferencing.
References
References vs pointers
int x = 42;
// Reference — must be initialized, cannot be null, cannot be reseated
int& ref = x;
ref = 100;
std::cout << x; // 100
// Pointer — can be null, can be reseated
int* ptr = &x;
int y = 99;
ptr = &y; // now points to y
// Function parameters
void by_value(int n) { n = 0; } // copies, original unchanged
void by_ref(int& n) { n = 0; } // modifies original
void by_ptr(int* n) { *n = 0; } // modifies through pointer
void by_cref(const int& n) { } // read-only reference (no copy)
Pass by const& for read-only access to large objects (avoids copying). Pass by & when the function needs to modify the argument. Pass by value for small types (int, char, bool).
Pointer Arithmetic
Array traversal with pointers
int arr[] = {10, 20, 30, 40, 50};
int* p = arr; // arrays decay to pointers
std::cout << *p; // 10
std::cout << *(p + 2); // 30
p++;
std::cout << *p; // 20
// Iterate with pointers
for (int* it = arr; it != arr + 5; ++it) {
std::cout << *it << " ";
}
p + n advances by n * sizeof(type) bytes. This is how C-style arrays work under the hood.
Dynamic Memory
new/delete — manual heap allocation
// Single object
int* p = new int(42);
delete p;
// Array
int* arr = new int[100];
delete[] arr; // delete[] for arrays, not delete
// The problem: forgetting delete = memory leak
// The solution: smart pointers (see memory management)
Raw new/delete should be avoided in modern C++. Use smart pointers or containers instead.
void Pointers
Generic pointer type
void* generic = &x;
// Must cast to use
int* typed = static_cast<int*>(generic);
std::cout << *typed;
// Common in C APIs
void callback(void* user_data) {
auto* config = static_cast<Config*>(user_data);
// use config...
}
void* cannot be dereferenced directly. Cast it to the correct type first. Prefer templates in C++ — they provide type safety.