5

I have a function that takes a double pointer to a struct and assigns a value. However I get an "access violation writing location ..." when trying to access the member member1. This is my code:

struct mystruct{
  unsigned int member1;
  void * data;
};

int main(){

  mystruct **foo = new mystruct *;
  bar(foo);

}

void bar(unsigned int val, mystruct ** foo)
{
    (*foo)->member1 = val;
}
billz
  • 44,644
  • 9
  • 83
  • 100
tzippy
  • 6,458
  • 30
  • 82
  • 151
  • 9
    Forget `**` in C++, trust me you will not lose anything. – masoud Oct 01 '13 at 08:15
  • Note: I changed the C tag to C++ as he was using `new` but maybe he want's C code and jsut isn't knowing new is not part of C – dhein Oct 01 '13 at 08:27

4 Answers4

5

You just created a new mystruct pointer. That means:

You get allocated a memory block, large enough to hold a address, and assign it to the pointer which is pointing to a pointer that points to a mystruct member. That doesn't mean, that there is a valid address hold in the pointer which you expect to be pointing to a mystruct element. Even more currently there isn't even a valid address, where the pointer to the pointer is pointing on, as you just assigned a valid memory area to it, what doesn't mean there is a usefull address stored in.

So at all, what you want is:

You want a pointer which has a valid memory block to store a address in of another pointer, which is pointing to a valid memory area, where is a (probably valid) mystruct stored in.

What you are doing is: you are requesting a memory area where you COULD (what you aren't even doing) store a poitner to another pointer... and so on.

so what you should do is:

mystruct **foo = new mystruct *;
*foo = new mystruct;
dhein
  • 6,431
  • 4
  • 42
  • 74
4

I have a function that takes a double pointer

That's weird. If you can, simplify it to take a reference:

void bar(unsigned int val, mystruct & foo) {
    foo.member1 = val;
}

mystruct foo;
bar(42, foo);

If you don't have control over the function, then you'll need an object at the end of the pointer trail:

mystruct foo;
mystruct * pointless = &foo;
bar(42, &pointless);

You can, of course, mess around with new if you really want to; but that's almost certainly a bad idea.

Your code allocates and leaks a pointer, but doesn't initialise it to point to a valid object; so dereferencing it gives undefined behaviour.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
3

This C-style function:

void bar1(mystruct* foo) {
    foo->member1 = val;
}

takes an argument of type mystruct* in order for changes made to object that foo points to to be visible to the caller. However this function:

void bar(unsigned int val, mystruct ** foo) {
    (*foo)->member1 = val;
}

takes pointer to mystruct* (most likely) in order to to modify the pointer itself, i.e. in order for changes made to the pointer to be visible to the caller and thus probably meant to be used this way:

mystruct* foo = new mystruct;
bar(&foo);

... yet usually it is reasonable to avoid dynamic allocation and passing pointers should be rather rarity than a common practice. Prefer objects with automatic storage duration over the dynamically allocated ones and prefer passing by reference over passing by pointer (when possible).

LihO
  • 41,190
  • 11
  • 99
  • 167
2

The other answers are good advice. But also, if you have control over the bar function, and need to be able to change in bar to what object your mystruct * pointer points to (which is probably the reason why you have a double pointer in the first place), then the cleanest approach is to use the following signature for bar:

void bar(unsigned int val, mystruct * &foo);

It passes by reference a pointer, so you are able to change to what object the pointer points to, without sacrificing readability of the code, for instance:

int main()
{
    mystruct * foo = new mystruct;
    bar(42, foo);
}

void bar(unsigned int val, mystruct * &foo)
{ 
    foo->member1 = val;
    foo = new mystruct;
}

A complete usage scenario without memory leak could be:

int main()
{
    // allocate dynamically a mystruct whose member1 is equal to 1.
    mystruct * foo1 = new mystruct;
    mystruct * foo2 = foo1;
    foo1->member1 = 1;

    // pass by reference foo1
    bar(42, foo1);
    // here, foo1->member1 == 42 and foo2->member1 == 10

    // free memory
    delete foo1; // the one allocated in bar()
    delete foo2; // the one allocated in main()
}

void bar(unsigned int val, mystruct * &foo)
{ 
    // modify the object allocated in main()
    foo->member1 = 10;

    // allocate dynamically a mystruct, store its address in foo
    foo = new mystruct; 
    foo->member1 = val; 
}
Boris Dalstein
  • 7,015
  • 4
  • 30
  • 59
  • My answer also fits that way it just doesn't do it by reference, more it does it the way, the OP mentioned it. but anyway +1 for you. – dhein Oct 01 '13 at 09:04
  • 1
    Yes, your answer is my favourite with Liho's one, I already +1'ed them, but since it is good practice to pass by reference whenever possible, I figured it was useful to tell the OP how to do in this case ;-) – Boris Dalstein Oct 01 '13 at 09:11
  • @Zaibis But you were right on one point, I changed "the correct approach" by "the cleanest approach". All are correct ;-) – Boris Dalstein Oct 01 '13 at 09:18