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
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