0

As the question says, can someone explain the behavior below

class X{
   public:
    int *p;
    void *q;
    void goo(int v);
};

void X::goo(int v){
    p = &v;
    q = &v;
}

X foo(int v){
    X x;
    x.p = &v;
    x.q = &v;
    return x;
}

int main(int argc, char const *argv[])
{
    X x = foo(10);
    cout << *x.p << " " << *(int *)x.q << endl;
    x.goo(3);
    cout << *x.p << " " << *(int *)x.q << endl;
    return 0;
}

OUTPUT

10 0
3 32764

The void pointer behavior is that of what is expected when the variables
are passed by reference...

class X{
public:
    int *p;
    void *q;
    void goo(int &v);
};

void X::goo(int &v){
    p = &v;
    q = &v;
}

X foo(int &v){
    X x;
    x.p = &v;
    x.q = &v;
    return x;
}

int main(int argc, char const *argv[])
{
    int a = 10;
    X x = foo(a);
    cout << *x.p << " " << *(int *)x.q << endl;
    int b = 3;
    x.goo(b);
    cout << *x.p << " " << *(int *)x.q << endl;
    return 0;
}

OUTPUT

10 10
3 3

Why in the first case, the behavior differs between void and int pointer. I think what I am lacking is a proper understanding of void pointer in c/c++. Can someone explain this?

  • `X::foo()` and `goo()` both store the address of variables of automatic storage duration, and those cease to exist when the function returns. The code that is producing output is dereferencing those pointers, so has undefined behaviour. When behaviour is undefined, any behaviour is possible - one possibility being, as you are seeing, different results for different types of pointer. – Peter May 17 '19 at 11:13
  • @Peter I also thought that the variable **v** in the functions gets destroyed, so the pointer is referencing to some garbage value, but why it works in the case of integer pointer. – Akash Chandra May 17 '19 at 11:17
  • @Peter, I think I got it, so as you say different behaviors for different types of pointers, so my guess is that in case of `void*` pointer we won't be seeing the abnormality anytime. – Akash Chandra May 17 '19 at 11:23
  • The behaviour is UNDEFINED, so any behaviour is possible - including seeming to work in one case and not in another. The reason it works for `void *` but not for `int *` will be specific to your compiler, host system, etc. Completely different behaviour may occur if the code is built with a different compiler, with different optimisation settings, or if the program is run at a different time. I you assume "in the case of `void*` pointer we won't be seeing the abnormality" you will leave a bug lurking in your program - and the risk of it being found in future. – Peter May 17 '19 at 12:05

2 Answers2

2

In:

X foo(int v){
    X x;
    x.p = &v;
    x.q = &v;
    return x;
}

It takes the address of local variable v which gets destroyed when the function returns and you end up with invalid pointers. Dereferencing such pointers is undefined behaviour.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • I had the same in mind but why in the first case, it works for the integer pointer?? – Akash Chandra May 17 '19 at 11:18
  • 1
    That's the nature of undefined behaviour: sometimes it might work. – Bathsheba May 17 '19 at 11:22
  • @AkashChandra `cout << *x.p << " " << *(int *)x.q << endl;` is multiple calls to `operator<<` and one of these eventually overwrites the memory that used to be occupied by local variable `v`. – Maxim Egorushkin May 17 '19 at 11:30
  • @Bathsheba thanks for the info, my question was specifically to know the reason why it didn't work for the void pointer. I thought there would be any specific reason, regarding how void pointer works internally. But now I got it, the behavior itself is undefined and it depends on the code and state of memory at the time of executing the code. – Akash Chandra May 17 '19 at 11:34
0

It's got nothing to do with void*, in foo() you're taking the address of a local variable that gets destroyed. That's undefined behavior and anything can happen.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54