› Module 4: Pointers, References & Memory › 4.4 Dynamic Memory (new / delete)
M O D U L E

Module 4: Pointers, References & Memory

The concepts that make C++ powerful — and infamous: memory addresses, pointers, references, stack vs heap, and smart pointers.

4.1 Pointers

A pointer is a variable that stores a memory address instead of an ordinary value — specifically, the address of another variable.

The & operator retrieves an address ("address-of"), and the * operator, applied to a pointer, follows that address to reach the value stored there ("dereference").

Pointers are the foundation of dynamic memory allocation, linked data structures such as lists and trees, and passing large data around efficiently without copying it.

int x = 10;
int* p = &x;     // p holds the memory address of x
cout << *p;     // 10 -> dereferencing p gives x's value
*p = 20;        // changes x through the pointer
cout << x;      // 20
int x = 10; address: 2000 int* p = &x; p stores 2000 points to (address) int& r = x; r is an alias for x same memory, other name
Figure 4.1 — A pointer stores an address; a reference is an alias

4.2 References

A reference is an alias — simply another name for a variable that already exists.

Unlike a pointer:

  • A reference can never be null (it must be bound to a valid object upon initialization).
  • Once created, it can never be reseated to refer to something else.

References are most commonly used as function parameters, letting a function modify the caller's original variable directly without the overhead of copying large objects.

void doubleIt(int& n) { // n is a reference to the caller's variable
    n = n * 2;
}

int val = 5;
doubleIt(val);
cout << val; // 10 (val was modified in place!)

4.3 Stack vs Heap

C++ programs use two very different regions of memory:

  • The Stack: Stores local variables and function call frames — it is fast, automatically managed by the compiler, and memory is freed the instant a function returns. The stack grows downwards in memory.
  • The Heap: A much larger pool of memory that you control manually with new and delete (or smart pointers) — objects placed there live until you explicitly free them, which gives you flexibility but is also the single most common source of memory leaks. The heap grows upwards in memory.
STACK grows down ↓ returns automatically freed local var: x function frame HEAP new Object() manually managed freed with delete / smart ptr ↑ grows up
Figure 4.2 — Stack: automatic and fast. Heap: manual and flexible.

4.4 Dynamic Memory (new / delete)

Sometimes a program doesn't know how much memory it will need until it is actually running — for example, when an array's size depends on runtime user input.

The new keyword allocates memory on the heap at runtime and returns a pointer to it. That memory stays reserved until you explicitly call delete on it; forgetting to do so causes a memory leak, since the program has lost its only reference to memory it never released.

int* p = new int(42);   // allocate a single int on the heap
cout << *p;            // 42
delete p;               // free single object memory

int* arr = new int[10]; // allocate an array of 10 integers
delete[] arr;           // free an array (note the square brackets [])
Common Pitfall (from the Guide):

Mismatching new/delete with new[]/delete[] causes undefined behavior and heap corruption. Always use delete[] for anything allocated with new[].

4.5 Smart Pointers

Manually pairing every new with a matching delete is notoriously error-prone: miss one and memory leaks; delete twice (double-free) and the program crashes with a segmentation fault.

Smart pointers from <memory> wrap a raw pointer and automatically delete the memory once it is no longer needed (RAII principle):

  • unique_ptr<T>: Allows exactly one owner at a time. Ownership cannot be copied, only moved.
  • shared_ptr<T>: Allows multiple owners through reference counting, freeing the memory only once the very last owner goes out of scope.
  • weak_ptr<T>: Observes a shared_ptr without incrementing its reference count, which helps break cyclic references that would otherwise leak memory forever.
#include <memory>
using namespace std;

unique_ptr<int> p1 = make_unique<int>(10);
shared_ptr<int> p2 = make_shared<int>(20);
// No delete needed — freed automatically when leaving scope!
Auto-deletes memory when owner goes out of scope unique_ptr<T> single owner shared_ptr<T> ref-counted, shared weak_ptr<T> non-owning view owns owns (shared) observes Heap Object
Figure 4.3 — Smart pointers manage heap memory for you
MODULE COMPREHENSIVE QUIZ

Module 4 Final Quiz

Test your understanding across all 5 topics of this module with interview-grade questions, tricky edge cases, and code output predictions.

Take Module 4 Final Quiz →
Yukti Mascot