Skip to content

17 Beginner The Hundred

The Array That Filled Itself With Zeros

the same idiom twice; only one of them keeps its promise

#include <iostream>

int main() {
    int zeros[5] = {0};   // the classic way to zero an array
    int ones[5] = {1};    // ...so this is the way to fill it with ones

    std::cout << "zeros:";
    for (int v : zeros)
        std::cout << ' ' << v;

    std::cout << "\nones: ";
    for (int v : ones)
        std::cout << ' ' << v;

    std::cout << '\n';
}

Run it. What does the second line print?

Answer
zeros: 0 0 0 0 0
ones:  1 0 0 0 0

Only the first element is a one. The other four are zeros — same as always.

Why

A braced initializer is not a fill pattern; it is a list of values for the first elements, in order. Every element you didn't write a value for is value-initialized, which for int means zero. So int zeros[5] = {0}; was never zeroing the array because you wrote a 0 — it works because the four elements you omitted come out zero for free, and the one you wrote happened to agree. int ones[5] = {1}; gets exactly the same treatment: element 0 becomes 1, elements 1–4 become 0. The rule holds for any element type and any prefix length — int p[5] = {1, 2}; is 1 2 0 0 0, and std::string s[3] = {"hi"}; gives you "hi" followed by two empty strings.

The honest version of the zeroing idiom is int zeros[5] = {}; — no elements written, so all five are value-initialized. Neither GCC 11.5 nor Clang 18 says a word about the {1} line, even under -Wall -Wextra -Wpedantic.

The fix

Say "fill" when you mean fill:

int ones[5];
std::fill(std::begin(ones), std::end(ones), 1);   // 1 1 1 1 1

std::array<int, 5> gains;
gains.fill(1);                                    // 1 1 1 1 1

Takeaway: a braced initializer supplies a prefix of the elements — everything after it is value-initialized to zero, no matter what you put in the braces.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry