5

I found unexpected output of following program.

Here pointer ptr point to address of variable i and i hold the value 10. It means the value of ptr also 10. Next ptr increment once. It means now it hold value 11. But in the following program ptr prints 12.

#include <iostream>
using namespace std;    

int main()
{
    int i = 10;
    int *ptr = &i;
    int j = 2;
    j += *ptr++;

    cout<<"i : "<<i<<"\n";
    cout<<"j : "<<j<<"\n";
    cout<<"ptr : "<<*ptr<<"\n";
}

Output:

i : 10
j : 12
ptr : 12

So I don't understand why ptr prints 12 instead of 11?

msc
  • 33,420
  • 29
  • 119
  • 214

1 Answers1

15

The program has undefined behavior.

This statement

j += *ptr++;

is equivalent to

j += *( ptr++ );

So the pointer now points to after the variable i that is it does not point to a valid object.

Thus this statement

cout<<"ptr : "<<*ptr<<"\n";

invokes undefined behavior.

It happened such a way that the compiler placed the variable j after the variable i. However the order of the variables is unspecified by the C++ Standard.

For example the gcc compiler's output is the same as you showed.

i : 10
j : 12
ptr : 12

While the clang compiler's output is

i : 10
j : 12
ptr : 4201824

What you mean is the following

j += ( *ptr )++;

In this case the output will be

i : 11
j : 12
ptr : 11

Pay attention to that the outputted value of i is 11 because the variable i is outputted in the following sentence when the side effect was already applied to the variable.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 2
    Note for causal readers (Vlad already is aware of this): _"So the pointer now points to after the variable i that is it does not point to a valid object."_ It is okay to have a pointer point to after the variable, but it is NOT okay (undefined behavior) to dereference that pointer. So things like `std::all_of(ptr, ptr+1, somepredicate)` is okay on a pointer to a non-array single object. – Eljay Oct 25 '19 at 13:44
  • 1
    @Eljay: Even though the Standard allows for the creation of just-past pointers, and equality comparisons between arbitrary pointers, gcc and clang are both prone to act nonsensically if a pointer to one object and a pointer just past another are compared and found to be equal. – supercat Oct 25 '19 at 17:52
  • @supercat • My understanding is that `ptr` and `ptr+1` is okay, but comparing `ptr` and `some_other_ptr+1` is not okay. It's a very limited (but useful) case where `ptr+1` is allowed, which happens to work well with the ranged based algorithms for the single object as the `begin` and `end`. (Bottom line: the C++ abstract machine is not the same as one's actual computer; the optimizer can surprise in delightful ways. Assuming one finds "long, late night debug sessions" to be delightful.) I believe that all jibes with your point. – Eljay Oct 25 '19 at 18:12
  • 1
    @Eljay: The C Standard expressly allows for *equality* comparisons between arbitrary pointers, and I'm pretty sure the C++ Standard does as well. The C Standard even goes so far as to expressly recognize the possibility of a comparison between a just-past pointer for one object and a pointer to another object, noting that such a comparison will report the pointers equal if the second object directly follows the first. – supercat Oct 25 '19 at 18:28