You are likely witnessing the work of a (clever) optimizer:
Without the for
loop, you access the array elements with a fixed constant, a constant which the optimizer can easily proove will lead to an uninitialized value, which is also never used again. As such, it can optimize away actually reading the element from the uninitialized memory, because it is perfectly entitled to use some constant instead.
With the for
loop, you have a second usage of the values (through the use of a dynamic index), and the optimizer has to ensure that the undefined value you read from the array elements in the first cout
is the same as the one that is later read within the loop. Obviously, it does not try to unroll the loop - after that it would know how to optimize the reads away.
In any case, whenever you access an uninitialized value, that value is undefined, it can be anything, including zero (even though you are not yet invoking undefined behavior). Whenever you use such a value for memory access (uninitialized pointer etc.), you have undefined behavior at its worst.