5

I found something weird, I tested this code:

#include <iostream>
using namespace std;

int main() {
    int i=0, a[5];
    cin>>a[i++]>>a[i++]>>a[i++];
    for(int j=0; j<i; j++){
        cout<<a[j]<<endl;
    }
}

With this input:

1
2
3

And got the input reversed like this:

3
2
1

I thought its output should be the same as this code:

#include <iostream>
using namespace std;

int main() {
    int i=0, a[5];
    cin>>a[i++]; cin>>a[i++]; cin>>a[i++];
    for(int j=0; j<i; j++){
        cout<<a[j]<<endl;
    }
}

Anybody had experienced this before? Thanks.

-Edit-

Thanks all for the answers!!!

stenlytw
  • 938
  • 13
  • 18

5 Answers5

9

This feels like undefined behaviour and compiler dependent:

cin>>a[i++]>>a[i++]>>a[i++];

(masters, please correct me if I'm wrong)

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
  • It's undefined behavior. I'm not sure that I'd use the expression "compiler dependent" here, since that sounds more like "implementation defined" (which means that different implementations may do different things, but they have to document it). In particular, the results here may vary according to the optimization flags, or even code in the surrounding statements. – James Kanze Mar 06 '14 at 09:39
9

The behaviour of the statement cin>>a[i++]>>a[i++]>>a[i++]; is actually undefined. This is because there are no sequence points.

You don't know when i will be incremented and your output is therefore not surprising.

See http://en.wikipedia.org/wiki/Sequence_point

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • @juanchopanza Yes, but by the time the first `operator>>` is called, the number of `a[i++]` arguments that have already been evaluated is somewhere between 1 and 3. – fredoverflow Mar 06 '14 at 09:10
  • @FredOverflow Wouldn't that make the behaviour *unspecified*? – juanchopanza Mar 06 '14 at 09:20
  • @juanchopanza The order of evaluation of arguments is indeed unspecified, but if multiple arguments access the same object and at least one of them is a write, you get undefined behavior (unless there is a sequence point between the write and the read access). – fredoverflow Mar 06 '14 at 09:22
  • 3
    @juanchopanza Sequence points (or the sequenced before concept in C++11) create a partial ordering. All of the calls to `operator>>` are ordered after of the `a[i++]` which provides its argument, but there's no ordering of the `a[i++]` previous to the first call. (The calls to `operator>>` are ordered, since there is a data dependency: the first argument of the second call is the return value of the first.) – James Kanze Mar 06 '14 at 09:42
5
cin>>a[i++]>>a[i++]>>a[i++];

is just syntactic sugar for

cin.operator>>(a[i++]).operator>>(a[i++]).operator>>(a[i++]);

Now, the three calls to operator>> are definitely executed from left to right, but the three arguments a[i++] can be evaluated in any order. Let's call the arguments x, y and z:

cin.operator>>(x).operator>>(y).operator>>(z);

You might expect the compiler to substitute x, y and z as follows:

int& x = a[i];
i++;
int& y = a[i];
i++;
int& z = a[i];
i++;

But in fact, the compiler is give much more freedom. In your case, it chose:

int& z = a[i];
i++;
int& y = a[i];
i++;
int& x = a[i];
i++;

And as James Kanze points out, it could also have chosen:

int& x = a[i];
int& y = a[i];
int& z = a[i];
i++;
i++;
i++;
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • Actually, given that we have undefined behavior, the compiler is free to do anything it wishes, including generate code which crashes. (G++ does this in some cases, when it recognizes undefined behavior.) More likely, the compiler can do something equivalent to `int &x = a[i], &y = a[i], &z = a[i]; i += 3;`. – James Kanze Mar 06 '14 at 09:45
2

When you modify and use variable inside the same statement, That results in Undefined behaviour. i is modified 3 times and accessed 3 times in statement below.

cin>>a[i++]>>a[i++]>>a[i++];

I guess below code will work fine.

#include <iostream>
using namespace std;
int main() {
    int i=0, a[5];
    cin>>a[0]>>a[1]>>a[2];

    i=3;

    for(int j=0; j<i; j++){
    cout<<a[j]<<endl;
}
}
Singh
  • 361
  • 1
  • 8
1

As already was said the code has undefined behaviour because the order of evaluation of function arguments are not specified and as the result applying of the side effects of postincrement operators are not sequenced in the deterministic way.

Howevrr I will explain the result.

Expression

cin>>a[i++]>>a[i++]>>a[i++];

is equivalent to the followiung expression if we will use functional notation

cin.operator >>( a[i++] ).operator >>( a[i++] ).operator >>( a[i++] );

The order of evaluation of function arguments are not specified. So some compilers evaluate arguments right to left while others - left to right.

It is obvious that your compiler evaluates function arguments right to left. The first is evaluated the argument of the right most function

cin.operator >>( a[i++] ).operator >>( a[i++] ).operator >>( a[0] );

After evaluation of the argument the compiler applies the side effect. i becomes equal to 1. Then the compiler evaluares the argument of the second function and you get

cin.operator >>( a[i++] ).operator >>( a[1] ).operator >>( a[0] );

And at last after evaluation the argument of the first function call there will be

cin.operator >>( a[2] ).operator >>( a[1] ).operator >>( a[0] );

and variable i will be equal to 3.

However as the order of evaluation of function arguments as I said are nor specified other compilers can represent this expression as

cin.operator >>( a[0] ).operator >>( a[1] ).operator >>( a[2] );

So the result can be different and the behaviour of the program is undefined.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335