← Back to all posts

06 C++ Notes

Arrays

C++ Notes


Declaration and Use

What Is an Array

Declaration

Declaration and Assignment Together

FormResult
int arr[5]{10, 20, 30, 40, 50};Fully initialized at declaration using braces.
int arr[5]{1, 2};Partial brace initialization. arr[0]=1, arr[1]=2, every remaining element becomes 0.
int arr[5]{};All elements zero-initialized. No garbage values, predictable and safe. This is the preferred practice.
int arr[]{1, 2, 3};Size is deduced by the compiler from the initializer list. Valid, but an explicit size is usually clearer to read.

Stack Arrays: Size Must Be Compile-Time

InvalidValid
int x = 5;
int arr[x]; // runtime variable

size_t n = 5;
int arr[n]; // runtime variable

const int x = 5;
int arr[x]; // const != compile-time
constexpr int x = 5;
int arr[x]; // compile-time constant

int arr[5]; // literal size

int arr[]{1, 2, 3}; // deduced size

Some compilers like g++ may allow runtime-sized arrays as an extension, but this is not standard C++. Relying on it causes "works on my machine" problems the moment the code gets compiled somewhere else, like on a different compiler or in a CI pipeline that follows the standard strictly.


Code Example: main.cpp

C++
#include <iostream>

int main() {
    // 1. Declaration (garbage values at each index)
    int scores[10];

    // 2. Assignment after declaration (only = allowed)
    scores[0] = 33;
    scores[1] = 45;

    // 3. Declaration + assignment (brace initialization)
    int arr1[5]{10, 20, 30, 40, 50};

    // 4. Partial brace initialization (remaining elements become 0)
    int arr2[5]{1, 2};

    // 5. Zero-initialized array (recommended, no garbage values)
    int arr3[5]{};

    // 6. Size deduction by compiler (valid but less readable)
    int arr4[]{1, 2, 3};

    // 7. Accessing elements by index
    std::cout << "arr1[0]: " << arr1[0] << "\n";   // prints: 10
    std::cout << "arr1[4]: " << arr1[4] << "\n\n"; // prints: 50

    // 8. Enhanced for loop (read-only iteration)
    std::cout << "arr1 elements: ";
    for (int value : arr1) {
        std::cout << value << " "; // prints: 10 20 30 40 50
    }
    std::cout << "\n";

    // 9. Calculation using enhanced for loop
    int sum{0};
    for (int value : arr1) {
        sum += value;
    }
    std::cout << "Sum of arr1: " << sum << "\n"; // prints: 150

    return 0;
}

Size of Array

For int arr[]{1, 2, 3}; (int is 4 bytes)Returns
std::size(arr)3
sizeof(arr)12 (total bytes)
sizeof(arr) / sizeof(arr[0])3

Once you have the element count, use it in loops, pass it to functions, or use it as a boundary check.

Prefer std::size() in modern C++ (C++17 and later). It's cleaner, less error-prone, and clearly expresses intent. The sizeof division trick is a pre-C++17 workaround, kept alive mostly by codebases that predate the standard.


Code Example: main.cpp

C++
#include <iostream>
#include <iterator>  // required for std::size() in C++17

int main() {
    int arr[]{1, 2, 3};

    std::cout << "std::size(arr):               " << std::size(arr)                        << '\n'; // prints: 3
    std::cout << "sizeof(arr):                  " << sizeof(arr)                           << '\n'; // prints: 12 (3 ints x 4 bytes each)
    std::cout << "sizeof(arr)/sizeof(arr[0]):   " << (sizeof(arr) / sizeof(arr[0])) << '\n'; // prints: 3

    return 0;
}

Array of Char

C-Strings and Null Termination

Unsafe examples: char arr1[]{'h','a','s','s','a','n'}; has no null terminator, unsafe to print. char arr2[6]{'h','a','s','s','a','n'}; has a size of exactly 6 with no room for '\0', also unsafe to print.

Making a Valid C-String

MethodHow
Explicit null terminatorAdd '\0' manually as the last element: char arr[7]{'h','a','s','s','a','n','\0'};, safe to print.
Oversize by 1 and use brace initLeave the last element unspecified. Brace initialization zeroes it automatically: char arr[7]{'h','a','s','s','a','n'};, the last element becomes '\0' from brace init, safe to print.
String literal initializationThe compiler appends '\0' automatically and deduces the size too: char arr[]{"Hello!"};, safe to print.

String literal initialization is the cleanest of the three. The compiler handles both size and null termination for you, so there's nothing left to miscount.

User Input into Char Arrays

In real code, prefer std::string over char arrays. It manages memory and null termination automatically and is far safer to work with, char arrays are worth understanding for exactly the reasons above, but they're rarely the right default choice once std::string is available.

Size Functions Compared

ExpressionWhat It Returns
std::size(char_array)Number of elements in the array, including the null terminator slot.
sizeof(char_array)Memory used by the array in bytes, the same as the element count for char since each char is 1 byte.
str.size()Length of a std::string in characters, not counting the null terminator.
sizeof(std::string)Size of the string object itself in bytes, typically 32 bytes on 64-bit systems, not the length of the text it holds.

Code Example: main.cpp

C++
#include <iostream>

int main() {
    // not C-strings: no null terminator, unsafe to print
    char arr1[]{'h','a','s','s','a','n'};      // no '\0'
    char arr2[6]{'h','a','s','s','a','n'};    // size 6, no room for '\0'
    // std::cout << arr1;  // unsafe, prints garbage
    // std::cout << arr2;  // unsafe, prints garbage

    // oversize by 1: brace init zeroes the last element to '\0'
    char arr3[7]{'h','a','s','s','a','n'};
    std::cout << arr3 << '\n'; // prints: hassan

    // string literal: compiler appends '\0' automatically
    char arr4[]{"Hello!"};
    char arr5[]{"Hello, World!"};
    std::cout << arr4 << '\n'; // prints: Hello!
    std::cout << arr5 << '\n'; // prints: Hello, World!

    // user input: getline for char arrays (different from std::getline for std::string)
    char name[20];  // large enough to hold input + '\0'
    std::cout << "Enter your name: ";
    std::cin.getline(name, 20); // reads up to 19 chars, appends '\0' automatically
    std::cout << "You entered: " << name << '\n'; // prints whatever was entered

    return 0;
}

Closing

Arrays are simple until they meet raw memory: fixed size, compile-time only on the stack, and a char array is only safely printable if it's actually null terminated. Next up, pointers, where all of this stops being an implementation detail and becomes the main subject.

← Previous 05 - Loops Next → 07 - Pointers, Part 1: Declaration and Memory