0

In the following code:

 #include<iostream>
    using namespace std;
    int main()
     {
           int A[5] = {10,20,30,40,50};

                     // Let us try to print A[5] which does NOT exist but still
      cout <<"First A[5] = "<< A[5] << endl<<endl;

                    //Now let us print A[5] inside the for loop

    for(int i=0; i<=5; i++)
    {
      cout<<"Second A["<<i<<"]"<<" = "<<A[i]<<endl;
    }

     }

Output:

output of the above code

The first A[5] is giving different output (is it called garbage value?) and the second A[5] which is inside the for loop is giving different output (in this case, A[i] is giving the output as i). Can anyone explain me why?

Also inside the for loop, if I declare a random variable like int sax = 100; then A[5] will take the value 100 and I don't have the slightest of clue why is this happening.

I am on Windows, CodeBlocks, GNUGCC Compiler

Evg
  • 25,259
  • 5
  • 41
  • 83
wthrajat
  • 32
  • 6
  • 2
    Does this answer your question? [Accessing an array out of bounds gives no error, why?](https://stackoverflow.com/questions/1239938/accessing-an-array-out-of-bounds-gives-no-error-why) – alagner Jan 13 '22 at 09:52
  • 1
    @alagner: I think that's a simpler question. In this case, we see two different examples of Undefined Behavior. – MSalters Jan 13 '22 at 10:32

3 Answers3

4

Well you invoke Undefined Behaviour, so behaviour is err... undefined and anything can happen including what your show here.

In common implementations, data past the end of array could be used by a different element, and only implementation details in the compiler could tell which one.

Here your implementation has placed the next variable (i) just after the array, so A[5] is an (invalid) accessor for i.

But please do not rely on that. Different compilers or different compilation options could give a different result. And as a compiler is free to assume that you code shall not invoke UB an optimizing compiler could just optimize out all of your code and only you would be to blame.

TL/DR: Never, ever try to experiment UB: anything can happen from a consistent behaviour to an immediate crash passing by various inconsistent outputs. And what you see will not be reproduced in a different context (context here can even be just a different run of same code)

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • 1
    It's not just different compilers or different compilation options. Even running the exact same code on the exact same computer can produce varying results in the presence of Undefined Behavior. – MSalters Jan 13 '22 at 10:37
  • @MSalters: I know that you are right. In that specific case, I guess that the compiler has probably stored its variables one after the other and ignores array boundaries. So I would trust multiple runs of same code to have the same exact behaviour. I have just tried to add a precision in my post (what should be considered as a *context*) and have upvoted your comment to highlight it more. – Serge Ballesta Jan 13 '22 at 10:49
  • @SergeBallesta thanks a lot sir for the answer. I can't access A[5] as it doesn't exist, but what surprised me was I did NOT get any error which I was expecting but instead I got the value of "i" and I am still wondering why did it give "i", it could have given anything else. And if I declare a random variable inside the for loop, then A[5] will have that random variable's value. Sir I did not quite understand your "invalid-accessor-for-i point. Can you help me referring an article that explains it in detail? – wthrajat Jan 13 '22 at 11:50
  • 1
    @wthrajat: The standard says that accessing an array element outside of the array bounds invokes Undefined Behaviour. Error is a possible outcome of UB, but it is not the only one. What I meant by *invalid accessor* is that *in this specific case* any attempt to access `A[5]` actually accesses `i` but that it cannot be relied on, because of the *undefined behaviour*. – Serge Ballesta Jan 13 '22 at 12:27
  • @SergeBallesta: "in this specific case any attempt to access A[5] actually accesses i" : Why? Is it because "i" was declared just before calling out A[5]? If yes, then is it safe to conclude that when calling an array out of bounds, whatever we declare just before calling the array, that gives its value to the array. Sorry for dumb questions I just entered college and I am new to all this. You may ignore this as well i dont mind :) – wthrajat Jan 13 '22 at 15:57
  • 1
    @wthrajat: Why is it so in this specific case? Because of internals and implementation details of your compiler. It is **Undefined Behaviour** so it has no reason to be that way, it just happens to be that way in that run of that compilation. As I have already said do not try to experiment about UB and only learn how to avoid it. – Serge Ballesta Jan 13 '22 at 16:06
2

In your Program, I think "there is no any syntax issue" because when I execute this same code in my compiler. Then there is no any issue likes you.

It gives same garbage value at direct as well as in loop. enter image description here

  • There's no **syntax** issue, that's true. `A[5]` is syntactically valid. Integers can be used as array indices, and 5 is an integer. It's just too big, and that's not syntax. As for your compiler, see Serge Ballesta's answer. Different compilers can give different results. No surprise. **Anything** can cause different results in the presence of Undefined Behavior, including the phase of the moon. – MSalters Jan 13 '22 at 10:56
1

The problem is that when you wrote:

cout <<"First A[5] = "<< A[5] << endl<<endl;//this is Undefined behavior

In the above statement you're going out of bounds. This is because array index starts from 0 and not 1.

Since your array size is 5. This means you can safely access A[0],A[1],A[2],A[3] and A[4].

On the other hand you cannot access A[5]. If you try to do so, you will get undefined behavior.

Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.

So the output that you're seeing is a result of undefined behavior. And as i said don't rely on the output of a program that has UB.

So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.

For the same reason, in your for loop you should replace i<=5 with i<5.


1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.

Jason
  • 36,170
  • 5
  • 26
  • 60
  • Yes I am aware that I can't access A[5] as it doesn't exist, but what surprised me was I did NOT get any error which I was expecting but instead I got the value of "i" and I am still wondering why did it give "i", it could have given anything else but yeah, I understood now that this is UB. Thanks man. – wthrajat Jan 13 '22 at 10:19
  • @wthrajat You're welcome. Undefined behavior could have resulted in a seg fault, but in your case you did not get a seg fault and instead got some garbage value. Can you mark my answer(or any other) as correct by clicking on the check mark at the left side of the answer if it helped you understand the problem. – Jason Jan 13 '22 at 10:27