0
struct mystruct{
    int* x;
    float *y;
    string *z;
    mystruct(int* a,float* b, string *c): x(a), y(b), z(c){}
};
void* create(){
    int a = 1;
    float b = 2.2;
    string c = "aaa";
    mystruct x(&a, &b, &c);
    void* p = &x;
    return p;
}
void print(void *p){
    mystruct* p1 = static_cast<mystruct*>(p);
    cout << *p1->x  << " " << *p1->y << " "<<*p1->z<< endl;
}
int main(){
    cout << sizeof(mystruct) << endl;
    void* p1 =  create();
    print(p1);
    return 0;
}

The output of the code is like: 24 1 2.76648e+19 \203\304 ]\303fffff.\204UH\211\345H\201\354\220H\211}\270H\211. for which I suppose is: 24 1 2.2 aaa

I guess there is something wrong with the void* pointer casting, but I can not figure out why. Can someone help?

Feng
  • 67
  • 1
  • 9
  • 2
    You return a pointer to a *local variable*. Local variables goes out of scope once the function exits, and cease to exist. Pointers to such local variables will become invalid. Attempting to dereference that pointer will lead to [*undefined behavior*](http://en.cppreference.com/w/cpp/language/ub). And you dereference four such invalid pointers. In short, the problem have nothing to do with your casting. – Some programmer dude Jul 31 '17 at 08:27
  • The behavior of your entire program is undefined the moment you return and use `p`. – StoryTeller - Unslander Monica Jul 31 '17 at 08:27
  • 3
    https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope?noredirect=1&lq=1 – Mat Jul 31 '17 at 08:30
  • By the way, what is the *actual* problem you attempt to solve using the `void*` cast? Why are you doing it? In C++ you seldom need `void*`. And I also don't see any special need to use pointers for the structure members either. – Some programmer dude Jul 31 '17 at 08:30
  • thank you, so if I dynamically allocate some memory for those local variables, will that solve this issue? – Feng Jul 31 '17 at 08:31
  • @Someprogrammerdude umm, I think it is for encapsulation, I want to cast it to void* and pass those value to another function or interface, some suggestion? – Feng Jul 31 '17 at 08:32
  • The core mistake (expiring object lifetimes) pointed out both here and below are far more baseline than building a blackbox API for encapsulation. Walk, *then* run. – WhozCraig Jul 31 '17 at 08:42
  • Don't write C programs in C++. Use function overloading, templated functions or std::any. –  Jul 31 '17 at 08:44

1 Answers1

4

You creating undefined behaviour with this:

void* create(){
    int a = 1;
    float b = 2.2;
    string c = "aaa";
    mystruct x(&a, &b, &c);
    void* p = &x;
    return p;
}

There you initialize a mystruct with pointers to objects in the automatic storage scope (aka a local variable) of create. These objects cease to exist the very moment create is returned from and thus the pointers become invalid. Furthermore you're returning a pointer to a mystruct automatic storage object inside the create function as well. So that's kind of invoking undefined behaviour on top of undefined behaviour.

EDIT here's a proposed solution:

Stop using pointers inside the struct. It doesn't make sense to pass around pointers to int or float anyway, because pointers will always be larger than those. If you pass a pointer or a pointer to a function, either will be passed by copying the value, but with a pointer there's an extra indirection step. Where passing pointers to numeric types makes sense if you want to use them to pass a "reference" where the function can alter the values.

It also makes sense for passing pointers to structures so that not whole structures have to be copied around.

So I suggest you get rid of the pointers at a whole. You apparently do not yet understand how they work, and for that particular task you have there they are the wrong tool anyway.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • 1
    @JHBonarius The size of pointers is platform dependent (technically, the size of `int` and `float` is not exactly specified, either). To add to this answer: You barely need raw-pointers in C++ at all (unless you want to do some advanced low-level programming). Storing variables by value, storing arrays inside `std::vector` and passing objects by reference should cover 99% of a beginners use cases – chtz Jul 31 '17 at 08:51
  • 1
    @JHBonarius: On a 32bit machine float, int and pointer are all 32 bits. On a 64 bit machine (which is the majority of machines these days) following one of the standard ABIs then float and int still are 32 bits, but pointers are 64 bits (long ints are 64 bits with the usual 64 bit ABIs around, i.e. Windows, Linux and the *BSDs). If you want an integer to be definitely 64 bits you must either use int64_t or long long. – datenwolf Jul 31 '17 at 09:22