Skip to content
C++ Better Explained
Go back
Dynamic Arrays in C++: How to Create an Array With a Runtime Size

Dynamic Arrays in C++: Arrays When You Don’t Know the Size Yet

Your program asks the user how many test scores they want to enter. They say 47. But you wrote int scores[100]; and hoped for the best.

That’s the problem dynamic arrays solve: an array whose length is decided while the program is running, not while it’s being compiled.


Why a Normal Array Won’t Do

int n;
std::cin >> n;
int scores[n];   // ✗ not standard C++

You may be surprised that this compiles on g++ and clang. It’s a compiler extension called a variable-length array, borrowed from C. MSVC rejects it, and it isn’t in the C++ standard, so code that relies on it isn’t portable. Don’t build habits on it.

The array size in a regular declaration must be a compile-time constant, because the compiler needs to know exactly how many bytes to reserve on the stack before your program ever runs. See stack vs heap for why that restriction exists.


Creating a Dynamic Array With new

#include <iostream>

int main() {
    int n;
    std::cout << "How many numbers? ";
    std::cin >> n;

    int* scores = new int[n];      // allocated on the heap, size decided now

    for (int i = 0; i < n; ++i) {
        std::cout << "Score " << (i + 1) << ": ";
        std::cin >> scores[i];
    }

    int total = 0;
    for (int i = 0; i < n; ++i) total += scores[i];

    std::cout << "Average: " << static_cast<double>(total) / n << "\n";

    delete[] scores;               // give the memory back
    scores = nullptr;              // avoid a dangling pointer

    return 0;
}

new int[n] asks the operating system for enough heap memory to hold n integers and hands back the address of the first one. From there, scores[i] works exactly like a normal array — because array indexing was always pointer arithmetic underneath. Our guide to pointers in C++ unpacks that connection.

Note static_cast<double> in the average: without it, total / n performs integer division and quietly throws away the decimals.


The Three Rules You Must Not Break

1. new[] pairs with delete[], never plain delete.

int* arr = new int[10];
delete arr;      // ✗ undefined behaviour
delete[] arr;    // ✓

The square-bracket form tells the runtime to free the whole block (and, for class types, to run every element’s destructor). Mixing the forms is undefined behaviour — it may appear to work and corrupt the heap anyway.

2. Never delete the same pointer twice, and set it to nullptr afterwards so an accidental second delete is harmless. See nullptr vs NULL.

3. sizeof will lie to you.

int stack_arr[10];
int* heap_arr = new int[10];

std::cout << sizeof(stack_arr) << "\n";   // 40 — the whole array
std::cout << sizeof(heap_arr)  << "\n";   // 8  — just the pointer!

The size information simply isn’t part of the pointer’s type. You have to carry n around yourself, which is exactly the kind of bookkeeping that leads to bugs. More on this in how to get the size of an array.

If you're looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you're a complete beginner or looking to solidify your understanding. Just $19.

Initialising a Dynamic Array

Raw new int[n] leaves the memory uninitialised — it contains whatever garbage was there before. Reading it before writing is undefined behaviour:

int* a = new int[5];         // garbage values
int* b = new int[5]();       // all zeros — note the empty parentheses
int* c = new int[5]{1,2,3};  // 1, 2, 3, 0, 0  (C++11)

That tiny () is easy to miss and easy to forget. Default to new int[n]() unless you’re about to fill every slot immediately.


”Resizing” a Dynamic Array

There’s no realloc for new. To grow an array you allocate a new one, copy, and free the old:

#include <iostream>
#include <algorithm>   // std::copy

int* growArray(int* old, int oldSize, int newSize) {
    int* bigger = new int[newSize]();
    std::copy(old, old + oldSize, bigger);
    delete[] old;
    return bigger;
}

int main() {
    int size = 3;
    int* data = new int[size]{10, 20, 30};

    size = 6;
    data = growArray(data, 3, size);
    data[3] = 40;

    for (int i = 0; i < size; ++i) std::cout << data[i] << " ";
    std::cout << "\n";      // 10 20 30 40 0 0

    delete[] data;
    return 0;
}

Look at how much can go wrong here: forget the copy, mismatch the sizes, delete the wrong pointer, or return early and leak the whole block. This is genuinely hard to get right every time.


Just Use std::vector

Everything above is what std::vector does for you, correctly, every time:

#include <iostream>
#include <vector>

int main() {
    int n;
    std::cout << "How many numbers? ";
    std::cin >> n;

    std::vector<int> scores(n);          // n zero-initialised ints

    for (int i = 0; i < n; ++i) std::cin >> scores[i];

    scores.push_back(100);               // grows automatically
    std::cout << "Size: " << scores.size() << "\n";   // knows its own size

    return 0;                            // memory freed automatically
}

No delete[]. No separate size variable. No leak if an exception is thrown halfway through. std::vector is a dynamic array — it holds a new[] block internally and manages it properly.

So why learn new[] at all? Because you’ll read older code that uses it, because interviewers ask, and because understanding what vector does under the hood makes you better at using it. Write vectors; understand new[].


Quick Comparison

Static arraynew[]std::vector
Size decidedcompile timeruntimeruntime, changeable
Lives onstackheapheap (managed)
Frees itselfyesnoyes
Knows its sizevia sizeofno.size()
Can grownomanuallypush_back


Take Your C++ Further

If you’re looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you’re a complete beginner or looking to solidify your understanding. Just $19.

👉 Get the C++ Better Explained Ebook — $19

📋

Free Download: The 10 Mistakes Every C++ Beginner Makes

A free 1-page checklist that shows the exact traps that slow down every C++ beginner — so you can avoid them from day one.

🔒 No spam. Unsubscribe anytime.


Share this post on:

Written by

Sahil Bora

Software Engineer. Author and creator of C++ Better Explained.


Previous Post
How to Clear the Console Screen in C++ (Every Method Explained)
Next Post
std::list in C++: A Beginner's Guide to Linked Lists in the STL

Keep Learning