1
struct XYZ {
    XYZ *adress;
};

XYZ *Ex;
int main() {
    Ex = new XYZ[3];
    Ex->adress = (++Ex);
    cout << Ex->adress << endl;
    Ex->adress = (++Ex);
    cout << Ex->adress << endl;
    Ex->adress = (--Ex)->adress;
    cout << Ex->adress << endl;    

Output:

0105E424        
0105E428
0105E424
struct XYZ {
    XYZ *adress;
};

XYZ *Ex;

void copy_adress(XYZ *Ex) {
    Ex->adress = (++Ex);
}

int main() {
    Ex = new XYZ[3];
    copy_adress(Ex);
    cout << Ex->adress << endl;
    Ex->adress = (++Ex);
    cout << Ex->adress << endl;
    Ex->adress = (--Ex)->adress;
    cout << Ex->adress << endl;

Output:

CDCDCDCD
00A3E53C
CDCDCDCD

Can you tell me why this is happening, and how I can fix it?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
vmahth1
  • 203
  • 2
  • 9
  • On visual studio in debug mode the pattern `CDCDCDCD` means uninitialized heap memory. [https://stackoverflow.com/a/127404/487892](https://stackoverflow.com/a/127404/487892) – drescherjm May 05 '20 at 00:04
  • 1
    Probably what happens: `Ex` points to an array. When `copy_adress` is called, the parameter `Ex` ends up incremented before it is evaluated in the expression `Ex->adress`, causing the address to be stored in the field of the second array element. Upon returning to `main`, the global `Ex` still points to the first array element (it was not incremented), so the value of `Ex->adress` is uninitialized (the compiler set it to the distinctive `0xCDCDCDCD` pattern). **However, since the behavior is undefined, this is just conjecture.** – JaMiT May 05 '20 at 00:08
  • @JaMiT Isn't this fine in c++17? – cigien May 05 '20 at 00:08
  • 1
    @cigien Did that change make it in? Honestly, I haven't really kept up with this aspect of the language because I avoid these kinds of expressions for style reasons / code readability. (I did finally find that C++17 note at the end of the duplicate, but that was mentioned as a proposal, which sounds like it was not definitely in when that was written.) – JaMiT May 05 '20 at 00:13
  • @JaMiT I'm not 100% sure (I rarely am), but I'm pretty sure this is ok now. Definitely not code that should be written :) anyway, I voted to reopen the question. – cigien May 05 '20 at 00:15

2 Answers2

4

Pointers behave just like regular objects when you copy them, or pass them to a function. Changes to the copy are not reflected in the original. To make the changes in a function visible, you need to take it by reference:

void copy_adress(XYZ *&Ex) {
   Ex->adress = (++Ex);
}

Now, the 2 versions are equivalent.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • It [works](https://godbolt.org/z/MYumWC) only if the reference is there. – cigien May 05 '20 at 00:04
  • It would also avoid confusion to use a different name for the function parameter than the global variable – M.M May 05 '20 at 00:37
1

(This is supplemental information, cigien answered the main question)

There was some speculation in comments about the sequencing of Ex->adress = (++Ex). Since C++17, the right operand of = is sequenced-before the left operand. And since C++11 both operands are sequenced-before the assignment.

So ++Ex is completed, and then the new value of Ex is used for the computation Ex->address. Prior to C++17 this was undefined behaviour.

The second code example does have UB but for a different reason: reading uninitialized memory:

M.M
  • 138,810
  • 21
  • 208
  • 365