Is ++*ptr++ undefined behaviour in c++?

C++Language Lawyer

C++ Problem Overview


I have been asked the following question in a test (I didn't want to write it myself. The test asked it. I know its bad code still) about evaluating ++*ptr++

int Ar[ ] = { 6 , 3 , 8 , 10 , 4 , 6 , 7} ;
int *Ptr = Ar  ;
cout<<++*Ptr++  ;

However, I suspect this is undefined behavior since it can be both (++*ptr)++ or ++(*ptr++). Is it? I am not too well acquainted with documentation so I couldn't find anything.

C++ Solutions


Solution 1 - C++

> However I suspect this is undefined behaviour since it can be both (++*ptr)++ or ++(*ptr++). Is it?

Not really, unlike the runtime behavior, which gives ample leeway to implementors, in C++ parsing itself follows quite strict and well-defined rules1. Indeed, looking at the precedence rules, ++*Ptr++ is actually parsed as ++(*(Ptr++)).

This trick question instead is probably alluding to the undefined behavior of expressions such as i = ++i + ++i, where you have a value that appears multiple times in an expression, and is subjected to a modification by a side-effect of the expression itself. Such expressions are illegal, as, unless there's some operator that sequences the side effects2, the exact moment in which they are applied is not defined, so it's undefined exactly what values i would assume in the various points of the expression.

Still, there's no undefined behavior here, as all side effects in the expression operate on different values, which appear only once in the expression: the "inner" ++ affects Ptr, while the outer one affects the value pointed originally by Ptr, i.e. Ar[0].

++(*(Ptr++))
     ^^^^^____increments Ptr, returning its original value
   ^^^^^^^^______dereferences the original Ptr, AKA &Ar[0]
^^^^^^^^^^^^_______ increments Ar[0]

That being said, if I ever saw such an expression in a code base of ours I'd go to great lengths to find the author and make sure that this wouldn't happen again.


  1. If sometimes very bizarre and absurdly costly to implement. Still, there are instances of undefined behavior in the standard describing some corner cases of the parsing, but it's orders of magnitude less pervasive than "runtime" undefined behavior.
  2. A handy summary of those rules can be found here; interestingly, some extra guarantees have been added in C++17.

Solution 2 - C++

This

++*Ptr++;

doesn't cause U.B and is evaluated as ++(*(Ptr++))

  • ptr++; /* address post incremented i.e doesn't change here itself */
  • *ptr; /* dereference same address i.e value at location where ptr earlier pointed i.e 6 */
  • ++*ptr; /* value changed where ptr pointed i.e Ar[0] becomes 7 */

Note that post increments Ptr++ evaluated as

  • Ptr; /* Ptr doesn't change here itself in same expression */
  • Ptr = Ptr + 1; /* in next expression, Ptr considers the incremented one */

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHarmonicView Question on Stackoverflow
Solution 1 - C++Matteo ItaliaView Answer on Stackoverflow
Solution 2 - C++AchalView Answer on Stackoverflow