📦 Section 2 · Arrays & Pointers 🟡 Intermediate MODULE 09

Dynamic Memory — new & delete

⏱️ 25 min read
📖 Theory + Code
🧩 5 Quiz Questions
🏗️ 1 Challenge
Your progress in Section 280%
🎯 What you'll learn: The difference between stack and heap memory, how to allocate memory manually with new and new[], why you must always pair a new with a matching delete, what a memory leak and a dangling pointer actually are, and why modern C++ often reaches for std::vector instead.

Stack vs Heap Memory

So far, every variable you've declared — int x;, int arr[5]; — has lived on the stack: a region of memory that's automatically managed. When a function ends, its stack variables are automatically cleaned up. Fast, simple, but limited in size and lifetime.

The heap is a much larger pool of memory that you control manually. Memory on the heap stays allocated until you explicitly free it — even after the function that created it has returned. This is what makes the heap useful for data that needs to outlive a single function call, or whose size isn't known until the program is running.

📚
Stack
Automatic, fast, freed for you the moment a variable goes out of scope. Limited total size.
🗄️
Heap
Manual, flexible, much larger. You allocate it with new and you — and only you — must free it with delete.

Allocating a Single Value with new / delete

The new operator allocates memory on the heap and returns a pointer to it. When you're done with that memory, you must free it with delete — the exact counterpart to new.

heap_single.cpp — new & delete on One Value
C++
// heap_single.cpp
#include <iostream>
using namespace std;

int main() {
    int* score = new int;   // allocate one int on the heap
    *score = 95;

    cout << "Score: " << *score << endl;

    delete score;   // free the memory — every new needs a matching delete
    score = nullptr;   // avoid a dangling pointer

    return 0;
}
⚠️
The single most important rule in this lesson
Every single new must be paired with exactly one matching delete. Not zero, not two — exactly one. Setting the pointer to nullptr right after deleting it is a defensive habit that stops you from accidentally using freed memory later.

Allocating a Dynamic Array with new[] / delete[]

To allocate an array on the heap — one whose size can be decided while the program is running, not fixed at compile time — use new[]. It must be freed with delete[], using the square brackets to match.

heap_array.cpp — new[] & delete[]
C++
// heap_array.cpp
#include <iostream>
using namespace std;

int main() {
    int n = 5;
    int* arr = new int[n];   // allocate an array of 5 ints on the heap

    for (int i = 0; i < n; i++) {
        arr[i] = i * 10;
    }

    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    delete[] arr;   // must use delete[] for arrays allocated with new[]
    arr = nullptr;

    return 0;
}
💡
Match the brackets
If you allocate with new, free with plain delete. If you allocate with new[], free with delete[]. Mismatching them is undefined behavior — the brackets aren't decoration, they tell the runtime exactly how the memory was structured.

Memory Leaks — Why delete Matters

A memory leak happens when you allocate memory with new but never free it with delete. The memory stays reserved on the heap forever — even though your program has lost every pointer that could reach it — because nothing tells the operating system it's safe to reuse.

leak_example.cpp — DON'T DO THIS
C++ — BUG
// leak_example.cpp — DON'T DO THIS, this function leaks memory
#include <iostream>
using namespace std;

void leakyFunction() {
    int* data = new int[100];
    // ... data is used here ...
    // BUG: missing "delete[] data;" — this memory is never freed
}   // data (the pointer) goes out of scope, the address is lost, the 100 ints leak forever

int main() {
    leakyFunction();   // every call leaks another 100 ints worth of memory
    return 0;
}

The fix is simple: always free what you allocate, in every code path — including any early return statements. A correct version of leakyFunction() would end with delete[] data; before its closing brace.

⚠️
Why this matters
A single leak might seem harmless, but a leak inside a function that runs repeatedly — in a loop, a server, or a long-running application — steadily consumes more and more memory until the program slows down or crashes. Pairing every new with a delete is not optional discipline; it's a core requirement of writing correct C++.

Dangling Pointers — The Bug to Avoid

A dangling pointer is a pointer that still holds the address of memory that has already been freed. Using it — reading it, writing to it, or even just checking it carelessly — is undefined behavior.

dangling_pointer.cpp — DON'T DO THIS
C++ — BUG
// dangling_pointer.cpp — DON'T DO THIS, the bug is using ptr after delete
#include <iostream>
using namespace std;

int main() {
    int* ptr = new int(42);
    delete ptr;              // memory is freed here

    // BUG: ptr still holds the OLD address — this is a dangling pointer
    cout << *ptr << endl;   // undefined behavior — do NOT do this

    return 0;
}

The fix, shown earlier in this lesson, is to set the pointer to nullptr immediately after deleting it: delete ptr; ptr = nullptr;. Dereferencing a nullptr still crashes your program — but it crashes predictably and immediately, which is far easier to debug than the silent corruption a dangling pointer can cause.

Looking Ahead: std::vector

Manually pairing every new with a delete is important to understand — but in modern C++, most day-to-day dynamic arrays are built with std::vector instead, which you'll meet later in this course's STL section.

std::vector manages the heap for you
A std::vector allocates its own heap memory internally, grows automatically as you add elements, and frees that memory automatically when it goes out of scope — no manual new[] or delete[] required. Modern C++ style prefers it for most dynamic-array use cases. You're learning manual new/delete now because understanding what's happening underneath makes you a far stronger C++ programmer once you do start using std::vector.

Lesson Summary

Let's recap everything you learned in this lesson:

The stack is automatic and fast; the heap is manual and flexible.
new allocates a single heap value; free it with delete.
new[] allocates a heap array; free it with delete[] — the brackets must match.
Forgetting delete causes a memory leak — memory reserved forever with no way back.
Using a pointer after it's been deleted is a dangling pointer — always null it right after deleting.
Modern C++ often prefers std::vector, which manages heap memory automatically.
🧩 Knowledge Check — Lesson 9
Answer all 5 questions to test your understanding. Instant feedback on every answer.
1. Where does memory allocated with new live?
2. Which operator correctly frees memory allocated with new int[10];?
3. What happens if you forget to delete memory you allocated with new?
4. What is a dangling pointer?
5. What does modern C++ recommend using instead of manual new[]/delete[] for most dynamic arrays?
💪
Coding Challenge — Lesson 9
Apply what you learned · Intermediate Level

Now it's your turn to write real code. Complete the challenge below in your own C++ environment.

Challenge: Dynamic Array Sum 🧮

Write a C++ program called dynamic_sum.cpp that: declares a constant int n (for example, const int n = 6;), dynamically allocates an array of n integers with new[], fills it with values of your choice, computes and prints the sum of all elements, and then correctly frees the memory before the program ends.

Rules: Use new int[n] to allocate — do not use a fixed-size stack array. Free it with delete[] exactly once, and only after you're done using it. Set the pointer to nullptr after deleting it.
💡 Show hints if you're stuck
  • Allocate with int* arr = new int[n];
  • Fill it in a loop: arr[i] = ...; for i from 0 to n-1
  • Sum it in a second loop, adding arr[i] to a running total
  • Finish with delete[] arr; arr = nullptr; — the exact matching cleanup for new[]
Finished this lesson?
Mark it complete to track your progress.
🎉

Lesson 9 Complete!

You now understand manual memory management — the discipline that underlies every C++ program. Time to test everything from this section in the review quiz.

Module 09 of 26 Section 2 — Arrays, Strings & Pointers