Memory Management Complete Guide
Pointer Types Advanced Topic

C++ Pointers: Complete Guide to All Pointer Types

Master C++ pointers with comprehensive examples of all pointer types, memory management, smart pointers, pointer arithmetic, and practical applications. Learn efficient memory manipulation techniques.

Basic Pointers

Memory addresses

Advanced Pointers

Complex types

Smart Pointers

Memory safety

Pointer Arithmetic

Memory navigation

C++ Tutorial · Pointers

Pointers hold addresses—powerful and error-prone. This chapter demystifies *, &, nullptr, and pointer arithmetic so you can read systems code and interview answers confidently.

What you will learn

  • Declare pointers and assign addresses with &
  • Dereference safely and avoid null pointer bugs
  • Use pointer arithmetic on arrays
  • Combine const with pointers and references
  • Relate pointers to functions and dynamic memory

Why this topic matters

Pointers separate C++ beginners from engineers. They appear in linked lists, callbacks, and performance-critical APIs.

Key terms & indexing

C++ pointers nullptr C++ pointer arithmetic dereference C++

Understanding Pointers in C++

Pointers are powerful features of C++ that store memory addresses. They enable direct memory access, dynamic memory allocation, and efficient data manipulation. Mastering pointers is essential for advanced C++ programming.

Basic Pointer Memory Address

Stores memory address of a variable. Foundation of pointer concepts.

Advanced Pointers Complex Types

Pointers to pointers, function pointers, void pointers for flexibility.

Smart Pointers Automatic Management

Automatically manage memory, prevent leaks (C++11 and later).

Pointer Arithmetic

Navigate through memory using arithmetic operations on pointers.

Pointer Concept Visualization
Variable
int x = 42;
Value: 42
Address: 0x7fff5fbff8ac
Pointer
int* ptr = &x;
Stores: 0x7fff5fbff8ac
Points to: 42

Pointer stores memory address: ptr contains the address of x, allowing indirect access to its value.

Key Concepts:
  • Address Operator (&): Gets memory address of a variable
  • Dereference Operator (*): Accesses value at a memory address
  • Null Pointer: Pointer that doesn't point to any valid location
  • Memory Address: Unique location in computer's memory
  • Pointer Size: Same for all data types (typically 4 or 8 bytes)

1. Basic Pointers

// Declaration syntax:
data_type* pointer_name;

// Examples:
int* ptr1; // Pointer to integer
float* ptr2; // Pointer to float
char* ptr3; // Pointer to character
double* ptr4; // Pointer to double

Basic Pointer Examples

1. Declare and init
int x = 42;
int* p = &x;
2. Dereference
cout << *p;  // 42
3. Modify via pointer
*p = 100;
cout << x;
4. Address of pointer
cout << &p;
5. Null pointer
int* q = nullptr;
if (!q) cout << "null";
6. Reassign pointer
int a=1,b=2;
p=&a; p=&b;
Best Practices for Basic Pointers:
  • Always initialize pointers (use nullptr if not pointing to valid memory)
  • Check for null before dereferencing
  • Use const appropriately to prevent accidental modifications
  • Be aware of pointer sizes on different platforms (32-bit vs 64-bit)
  • Understand the difference between pointer value (address) and pointed value

2. Complete Pointer Types Comparison

The following table compares all pointer types in C++ with their syntax, use cases, and characteristics:

Pointer Type Syntax When to Use Characteristics
Basic Pointer int* ptr; Direct memory access, dynamic allocation Stores address, can be reassigned
Pointer to Pointer int** ptr; Dynamic 2D arrays, function arguments Points to another pointer, double indirection
Void Pointer (Generic) void* ptr; Generic functions, memory operations Can point to any type, cannot be dereferenced directly
Function Pointer int (*funcPtr)(int, int); Callbacks, event handlers, strategy pattern Points to function, enables runtime function selection
Array Pointer int (*arrPtr)[10]; Pointer to entire array, multi-dimensional arrays Different from pointer to first element
Const Pointer int* const ptr; Pointer that cannot be reassigned Constant pointer, variable data
Pointer to Const const int* ptr; Read-only access to data Variable pointer, constant data
unique_ptr (C++11) unique_ptr<int> ptr; Single ownership, resource management Automatically deletes, cannot be copied
shared_ptr (C++11) shared_ptr<int> ptr; Shared ownership, reference counting Automatically deletes when last reference goes
weak_ptr (C++11) weak_ptr<int> ptr; Break circular references Non-owning reference to shared_ptr
this Pointer this Within class methods to access members Implicit pointer to current object

3. Advanced Pointer Types

Pointer-to-Pointer Examples

1. int** type
int x=10;
int* p=&x;
int** pp=&p;
2. Double dereference
cout << **pp;
3. Change target
**pp = 99;
cout << x;
4. 2D via int**
int** m = new int*[rows];
5. Array of char*
const char* names[]={"A","B"};
6. pp null check
if (pp && *pp) cout << **pp;

Void Pointer Examples

1. void* storage
int n=5;
void* vp = &n;
2. Cast back to int*
int* ip = static_cast<int*>(vp);
cout << *ip;
3. malloc style
void* buf = malloc(16);
4. free after use
free(buf); buf=nullptr;
5. Any type address
float f=1.2f;
vp = &f;
6. sizeof still typed
cout << sizeof(int*);
Important Notes about Void Pointers:
  • Cannot be dereferenced directly (must be cast to appropriate type first)
  • No pointer arithmetic allowed on void pointers
  • Use with caution - type safety is the programmer's responsibility
  • Commonly used in low-level memory operations and generic programming
  • Modern C++ alternatives: templates, std::any (C++17)

4. Function Pointers

Function Pointer Examples

1. Declare fp
int (*fp)(int,int) = add;
2. Call via pointer
cout << fp(3,4);
3. typedef helper
using Fn = int(*)(int,int);
Fn f = add;
4. Pass to function
apply(5, 2, mul);
5. Array of callbacks
Fn ops[] = {add, sub};
6. nullptr guard
if (fp) fp(1,1);
Function Pointer Applications:
  • Callbacks: Event handlers, GUI programming
  • Strategy Pattern: Select algorithm at runtime
  • Sorting: Custom comparison functions
  • Plugin Architecture: Dynamic function loading
  • State Machines: Different behaviors for states

5. Smart Pointers (C++11+)

// Smart pointer syntax:
#include <memory>

// unique_ptr (exclusive ownership):
std::unique_ptr<Type> ptr = std::make_unique<Type>(args);

// shared_ptr (shared ownership):
std::shared_ptr<Type> ptr = std::make_shared<Type>(args);

// weak_ptr (non-owning reference):
std::weak_ptr<Type> wptr = sharedPtr;

Smart Pointer Examples

1. unique_ptr
auto p = make_unique<int>(42);
2. shared_ptr
auto a = make_shared<int>(10);
auto b = a;
3. weak_ptr observe
weak_ptr<int> w = a;
4. auto delete
} // unique_ptr frees memory
5. reset shared
a.reset();
b.use_count();
6. no raw new
// prefer make_unique
unique_ptr
  • Ownership: Exclusive
  • Copyable: No
  • Movable: Yes
  • Use when: Single owner needed
  • Overhead: Minimal
shared_ptr
  • Ownership: Shared
  • Copyable: Yes
  • Movable: Yes
  • Use when: Multiple owners needed
  • Overhead: Reference counting
weak_ptr
  • Ownership: None
  • Copyable: Yes
  • Movable: Yes
  • Use when: Break circular references
  • Overhead: Minimal

6. Pointer Arithmetic

Pointer Arithmetic Examples

1. Next element
int arr[]={1,2,3};
int* p=arr;
p++; cout<<*p;
2. Offset by n
cout << *(arr+2);
3. Subtract pointers
int* e = arr+3;
cout << e-arr;
4. Traverse C-string
char* s="hi";
while(*s) s++;
5. const char* literal
const char* msg = "OK";
6. Bounds caution
// do not pass end+1
Pointer Arithmetic Rules:
  • Adding n to a pointer moves it forward by n * sizeof(type) bytes
  • Subtracting n from a pointer moves it backward by n * sizeof(type) bytes
  • Pointer subtraction gives the number of elements between them
  • Pointer arithmetic only works within the same array or allocated memory block
  • Comparing pointers is only valid when they point to the same array

7. Best Practices & Common Pitfalls

Common Error Example Solution
Dereferencing Null Pointer int* ptr = nullptr; *ptr = 5; Always check for null before dereferencing
Dangling Pointer int* ptr = new int; delete ptr; *ptr = 10; Set pointer to null after deletion, use smart pointers
Memory Leak int* ptr = new int[100]; // No delete Always match new with delete, use RAII/smart pointers
Buffer Overflow int arr[5]; int* p = arr + 10; Check bounds, use containers like vector
Type Mismatch float* ptr = (float*)&intVar; Avoid unsafe casts, use proper type conversions
Pointer Arithmetic on Wrong Type void* ptr; ptr++; Don't use arithmetic on void pointers
Returning Local Variable Address int* func() { int x; return &x; } Don't return address of local variables
Double Free delete ptr; delete ptr; Set pointer to null after deletion
Best Practices
  • Always initialize pointers (use nullptr for empty)
  • Prefer smart pointers over raw pointers for ownership
  • Use const whenever possible
  • Check pointer validity before dereferencing
  • Match every new with exactly one delete
  • Use range-based for loops or iterators when possible
  • Document pointer ownership responsibilities
Performance Tips
  • Minimize pointer indirection (deep nesting hurts cache)
  • Use local pointers for frequently accessed data
  • Avoid unnecessary pointer arithmetic in tight loops
  • Consider reference types when ownership isn't needed
  • Profile before optimizing pointer usage

Modern C++ Pointer Guidelines

In modern C++ (C++11 and later), prefer smart pointers (unique_ptr, shared_ptr) for ownership, use raw pointers only for non-owning references, and leverage references when null isn't needed. Use std::array or std::vector instead of raw arrays.

Quick Quiz: Test Your Knowledge

What will be the output of this code?

int arr[] = {1, 2, 3, 4, 5};
int* ptr = arr + 2;
cout << *(ptr - 1) + *(ptr + 1);
A) 6
B) 7
C) 8
D) Segmentation fault

Summary & Key Takeaways

Pointer Fundamentals
  • Pointers store memory addresses
  • Use & to get address, * to dereference
  • Always initialize pointers
  • Check for null before dereferencing
  • Understand pointer size and platform differences
Smart Pointers (Modern C++)
  • unique_ptr: Exclusive ownership, cannot be copied
  • shared_ptr: Shared ownership with reference counting
  • weak_ptr: Non-owning reference to break circular dependencies
  • Prefer smart pointers for automatic memory management
  • Use make_unique and make_shared for creation
Advanced Pointer Types
  • Pointer to pointer: For multi-dimensional dynamic arrays
  • Void pointer: Generic pointers, requires explicit casting
  • Function pointer: Enables callbacks and runtime polymorphism
  • this pointer: Implicit pointer to current object
  • Const pointers: Various combinations for safety
Pointer Arithmetic
  • Adding n moves pointer by n * sizeof(type)
  • Use for array traversal and string manipulation
  • Pointer subtraction gives element count difference
  • Only valid within same allocated memory block
  • Essential for low-level memory operations

When to Use Different Pointer Types

  • Raw pointers: Non-owning references, legacy code, low-level operations
  • Smart pointers: Memory ownership, automatic cleanup, modern C++ code
  • References: When null isn't needed, function parameters, return values
  • Function pointers: Callbacks, strategy pattern, event systems
  • Avoid: Raw pointers for ownership, manual memory management in modern code

Next Steps

Mastering pointers is crucial for advanced C++ programming. Practice with pointer-based data structures (linked lists, trees), explore memory management patterns, learn about move semantics (C++11), and study the Standard Template Library (STL) containers that internally use pointers. Understanding pointers deeply will make you a more effective C++ programmer.

Frequently asked questions

What is nullptr?

C++11 null pointer literal—type-safe and preferred over NULL macro.

Can I add two pointers?

Generally no—only pointer ± integer or pointer − pointer (same array) is defined.

What is a dangling pointer?

Pointer to freed or out-of-scope memory—undefined behavior if dereferenced.