Home > Blockchain >  Why does the first element outside of a defined array default to zero?
Why does the first element outside of a defined array default to zero?

Time:12-15

I'm studying for the final exam for my intro to C class. Our professor gave us this problem for practice:

Explain why the code produces the following output: 120 200 16 0

using namespace std;
int main()
{
 int x[] = {120, 200, 16};
 for (int i = 0; i < 4; i  )
 cout << x[i] << " ";
}

The sample answer for the problem was:

The cout statement is simply cycling through the array elements whose subscript is being defined by the increment of the for loop. The element size is not defined by the array initialization. The for loop defines the size of the array, which happens to exceed the number of initialized elements, thereby defaulting to zero for the last element. The first for loop prints element 0 (120), the second prints element 1 (200), the third loop prints element 2 (16) and the forth loop prints the default array value of zero since nothing is initialized for element 3. At this point i now exceeds the condition and the for loop is terminated.

I'm a bit confused as to why that last element outside of the array always "defaults" to zero. Just to experiment, I pasted the code from the problem into my IDE, but changed the for loop to for (int i = 0; i < 8; i ). The output then changed to 120 200 16 0 4196320 0 547306487 32655. Why is there not an error when trying to access elements from an array that are outside of the defined size? Does the program just output whatever "leftover" data was there from the last time a value was saved to that memory address?

CodePudding user response:

I'm a bit confused as to why that last element outside of the array always "defaults" to zero.

In this declaration

int x[] = {120, 200, 16};

the array x has exactly three elements. So accessing memory outside the bounds of the array invokes undefined behavior.

That is, this loop

 for (int i = 0; i < 4; i  )
 cout << x[i] << " ";

invokes undefined behavior. The memory after the last element of the array can contain anything.

On the other hand, if the array were declared as

int x[4] = {120, 200, 16};

that is, with four elements, then the last element of the array that does not have an explicit initializer will be indeed initialized to zero.

CodePudding user response:

It does not default to zero. The sample answer is wrong. Undefined behaviour is undefined; the value may be 0, it may be 100. Accessing it may cause a seg fault, or cause your computer to be formatted.

As to why it's not an error, it's because C is not required to do bounds checking on arrays. You could use a vector and use the at function, which throws exceptions if you go outside the bounds, but arrays do not.

CodePudding user response:

It's causing undefined behaviour, this is the only valid answer. Your array x reserves memory on stack only for three integers, what you see in the output when reading fourth integer is unknown and on some systems/processors may cause hardware interrupt caused by trying to read memory which is not addressable (system don't know how to access physical memory at such address). The fact you get 0 is actually accidental. With the use of address sanitizer in clang (-fsanitize=address option) you can see this:

https://coliru.stacked-crooked.com/a/993d45532bdd4fc2

the short output is:

==9469==ERROR: AddressSanitizer: stack-buffer-overflow

You can investigate it even further, on compiler explorer :

https://godbolt.org/z/P5f57Yfvs

you will see that gcc generates following assembly for your array:

    mov     DWORD PTR [rbp-16], 120
    mov     DWORD PTR [rbp-12], 200
    mov     DWORD PTR [rbp-8], 16
    mov     DWORD PTR [rbp-4], 0

so, indeed - there is a fourth element with 0 value. But, see the optimization level of this example - its -g - so non optimizations. Start adding optimizations, lets say -O1 and you will get:

    mov     DWORD PTR [rsp 4], 120
    mov     DWORD PTR [rsp 8], 200
    mov     DWORD PTR [rsp 12], 16

More optimizations, may optimize your array entirely - putting it in registers.

  • Related