3

My teacher provided me with this code and it returns 31,40, but I am unable to figure out why. What is the reason for it returning what it does?

void main() {
    int *ptr;
    int arr[5] = { 10, 20, 30, 40, 50 };
    ptr = &arr[3];
    cout << ++*ptr-- << ", " << *ptr;
}
Cartier
  • 429
  • 4
  • 15
user2105306
  • 83
  • 1
  • 8
  • 8
    It is UB as there is no sequence point between the last `*ptr` and the first `ptr--`. – Jarod42 Jan 26 '15 at 17:10
  • 5
    `void main()` should be `int main()`; anyone trying to teach C++ should know that. Your title mentions "pointer arrays", but there is no "pointer array' in your program; there's an array, and there's a pointer. – Keith Thompson Jan 26 '15 at 17:10
  • 3
    @Jarod42: `<<` is overloaded; it's a function call, not a built-in operator. I *think* that provides enough sequence points to make the behavior well defined -- but it's butt-ugly code that should be re-written. – Keith Thompson Jan 26 '15 at 17:11
  • 4
    @KeithThompson: No, there's no call to `<<` between `++` and `--`, so no sequencing. – Mike Seymour Jan 26 '15 at 17:15
  • @MikeSeymour: I think you're right. (If it were my code, I'd spend my time rewriting it rather than figuring out whether its behavior is defined.) – Keith Thompson Jan 26 '15 at 17:17
  • @KeithThompson This function is from an exam. Sorry for "pointer arrays" stuff...my english sucks. – user2105306 Jan 26 '15 at 17:19
  • 1
    I get a different result with GCC 4.9.2 on Arch Linux: I get "41, 40". It's odd that you got "31,30" (especially because you got no space after the comma). Did you actually run this? What compiler? – David Grayson Jan 26 '15 at 17:19
  • @David Grayson Space is irrelevant. I've used Visual Studio. – user2105306 Jan 26 '15 at 17:21
  • 7
    Don't tell us the space is irrelevant. You should include the *exact* output in the question. If you aren't getting a space, that would indicate a serious problem somewhere. – Keith Thompson Jan 26 '15 at 17:24
  • 7
    @MikeSeymour `++*ptr--` is fine. The `++` and the `--` are not modifying the same thing (`--` on the pointer, `++` on the pointee). The problem is `ptr--` and `*ptr`. – T.C. Jan 26 '15 at 17:29
  • @Namfuak She's the one that makes the test, correct them and shows us _the bad grades_. Thug life. – user2105306 Jan 26 '15 at 17:33
  • @T.C. I think that too. Maybe that's the answer? – user2105306 Jan 26 '15 at 17:34
  • It looks to me like it should be either "41, 40" or "41, 30" but you said you got 31 for the first number? – Kenny Ostrom Jan 26 '15 at 17:57
  • @KennyOstrom Actually, in MinGW it shows me **41, 30**. Weird. – user2105306 Jan 26 '15 at 18:16
  • 1
    Maybe the question was to point out the bugs in the code.. before you bash the teacher.. – Neil Kirk Jan 26 '15 at 18:21
  • `void main()` means that, strictly speaking, the program is ill-formed. The lack of `#include ` means that the name `cout` and the `<<` operator aren't visible, so this code won't even compile. C++ compilers can still accept ill-formed programs, and the missing `#include` could simply mean that this is a code fragment, not a complete program. – Keith Thompson Jan 26 '15 at 19:20

2 Answers2

5
cout << ++*ptr-- << ", " << *ptr;

is

operator <<(cout.operator <<(++*ptr--), ", ").operator <<(*ptr);

The problem can be reduced to:

f(f(ptr--), ptr)

whereas order of evaluation between f(ptr--) and ptr is unspecified (and more specificaly between ptr-- and ptr).

So you got undefined behavior for the given code.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
3

The C++ standard states

Section 1.9/15 [intro.execution] : Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. (...) If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

++*ptr-- and *ptr are unsequenced subexpressions of the same expression using the same object: nothing guarantees that they are evaluated from left to right. So according to the standard, this results in undefined behaviour. Your result tend to show that your compiler chooses to evaluate first *ptr and then ++*ptr--.

Edit: ++*ptr-- is ++(*ptr--)). Here the operand of operator ++ also uses object ptr on which -- does a side effect. So this is undefined behaviour as well. It appears that in your case, the compiler first evaluates *ptr-- which results in 40 and a decremented ptr, and then applies ++ on the dereferenced decremented pointer (i.e. 30 incremented by 1).

Christophe
  • 68,716
  • 7
  • 72
  • 138