CppArrays

Arrays

An array is a fixed-size collection of elements of the same type, stored contiguously in memory. C++ inherits its array type directly from C, which makes it fast and simple — but also unforgiving. Unlike higher-level languages, C++ arrays do not know their own size at runtime and do not check whether an index is in range.

Declaring and initializing arrays

An array declaration specifies the element type, a name, and the number of elements in square brackets. Indexing is zero-based, so an array of size 5 has valid indices 0 through 4.

arrays_basics.cpp

CPP
#include <iostream>

int main() {
    int arr[5];                       // uninitialized — holds garbage values
    int scores[5] = {90, 85, 77, 60, 100};   // fully initialized
    int zeros[5] = {};                // all elements zero-initialized
    int partial[5] = {1, 2};          // {1, 2, 0, 0, 0}
    int inferred[] = {10, 20, 30};    // size deduced as 3

    for (int i = 0; i < 5; i++) {
        std::cout << scores[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}
Arrays decay to pointers in functions

When you pass an array to a function, it does not copy the array. Instead, the array “decays” into a pointer to its first element. This means the function has no way to know how many elements the array actually has — the size information is lost.

array_decay.cpp

CPP
#include <iostream>

void printSize(int arr[]) {
    // arr is really just an int*, NOT the original array type.
    std::cout << "Inside function: " << sizeof(arr) << " bytes" << std::endl;
}

int main() {
    int numbers[10] = {0};

    std::cout << "In main: " << sizeof(numbers) << " bytes" << std::endl;
    printSize(numbers);

    return 0;
}
The classic sizeof mistake
sizeof(numbers) inside main correctly reports the whole array's size in bytes (e.g. 40 bytes for 10 ints). But once that same array is passed into a function, sizeof(arr) reports the size of a single pointer (typically 8 bytes on a 64-bit system) — not the array. If you need the element count inside a function, you must pass it explicitly as a separate parameter, or prefer std::array or std::vector, which always know their own size.
Out-of-bounds access is undefined behavior

C++ does not check array bounds at compile time or at runtime. Reading or writing past the end of an array does not throw an exception — it simply accesses whatever memory happens to sit there, which may belong to another variable entirely.

out_of_bounds.cpp

CPP
int arr[3] = {1, 2, 3};

arr[5] = 99;       // undefined behavior: writes past the array's memory
int x = arr[10];   // undefined behavior: reads garbage, or crashes
No bounds checking — unlike Python
In Python, my_list[10] on a 3-element list raises an IndexError immediately. In C++, arr[10] on a 3-element array compiles fine and may run without any visible error at all — until it silently corrupts nearby memory or crashes much later, making the bug very hard to trace back to its source. Always ensure your indices stay within bounds; the compiler will not save you.
std::array — the safer modern alternative
C++11 introduced std::array (from the <array> header), a thin wrapper around a fixed-size C-style array. It behaves like a normal object: it knows its own size, does not decay when passed to functions, and works with the standard library's algorithms and range-based for loops.

std_array.cpp

CPP
#include <array>
#include <iostream>

void printAll(const std::array<int, 5>& arr) {
    // arr.size() still works correctly here — no decay!
    for (std::size_t i = 0; i < arr.size(); i++) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::array<int, 5> scores = {90, 85, 77, 60, 100};

    std::cout << "Size: " << scores.size() << std::endl;
    printAll(scores);

    // .at() performs bounds checking and throws std::out_of_range
    try {
        std::cout << scores.at(10) << std::endl;
    } catch (const std::out_of_range& e) {
        std::cout << "Caught: " << e.what() << std::endl;
    }

    return 0;
}

Feature

C-style array

std::array

Size known at runtime

No (decays to pointer)

Yes (.size())

Bounds checking

Never

Only with .at()

Works with algorithms

Partially

Fully

Header required

None (built-in)

<array>

Recommended for new code

Avoid when possible

Yes

Rule of thumb
Reach for std::array when the size is fixed and known at compile time, and std::vector (covered later) when the size can change at runtime. Plain C-style arrays are mostly worth understanding because so much existing C++ code — and all of C — still uses them.