1

I learned from this page: FAQ that, if you want to initialize a pointer inside a function, then you should pass a pointer to pointer, i.e, **p as foo1()

void foo1(int **p) {
    *p = malloc(100*sizeof(int)); // caller can get the memory
}

void foo2(int *p) {
    p = malloc(100*sizeof(int));  // caller cannot get the memory
}

However, a pointer means its value is the address it points to. Where does the memory allocated in foo2() go after leaving its scope?

I still can't figure out the different behavior between passing pointer to value and pointer to pointer? I search through SO but only found the solution or short description. Could anyone help in more detail?

Wayne
  • 641
  • 6
  • 11
  • 1
    read [Need of Pointer to pointer](http://stackoverflow.com/questions/18306935/need-of-pointer-to-pointer/18307020#18307020) – Grijesh Chauhan Sep 13 '13 at 09:20
  • *where does the memory go?* it's there in your box and goes nowhere (has no legs anyway) ... in terms of your code, it's **leaked**. – Walter Sep 13 '13 at 09:28
  • 2
    Note: `(int *) malloc(100);` is looks wrong (may be you introducing bug) because you are casting to `int*` I think your need `(int *) malloc(100 * sizeof(int));` – Grijesh Chauhan Sep 13 '13 at 09:29
  • 2
    @GrijeshChauhan perhaps you should suggest [not to cast result of malloc](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) too. – Dayal rai Sep 13 '13 at 09:31
  • 1
    @Dayalrai Yes Dayal you are correct! @ Wayne Avoid casting returned address from `malloc()` and `calloc()` functions – Grijesh Chauhan Sep 13 '13 at 09:38

7 Answers7

5

The memory allocated in foo2 is lost. This creates a memory leak because you have no idea where to find and use the allocated memory after foo2 returns.

Consider:

int *mymemory = NULL;
foo2(mymemory);
//mymemory is still NULL here. Memory has been allocated, 
//but you don't know at which address
//in particular, you will never be able to free() it

versus:

int *mymemory = NULL;
foo1(&mymemory);
//mymemory is now the address of the memory
//allocated by the function
dostuffwith(mymemory);
free(mymemory);
us2012
  • 16,083
  • 3
  • 46
  • 62
2

In your second example the memory allocated is leaked - once foo2 ends, there is no variable left that contains the address that was allocated, so it can't be freed.

You could also consider

void foo3 (int bar) {
    bar = 8;
}

int main (int argc, char *argv[]) {
    int x = 0;
    foo3(x);
    printf("%d\n", x);
    return 0;
}

when foo3 ends, x is still 0 - the change to the contents of bar in foo3 don't affect the outer variable that was passed in. You're doing exactly the same when you pass in a single pointer - you're assigning the address of some memory to it, but then losing that address when the function exits.

Vicky
  • 12,934
  • 4
  • 46
  • 54
2

To better understand indirection levels in C, it can be instructive to look at how the compiler organizes its memory.

Consider the following example :

void function1 (int var1, int var2) { ... }

In this case, function1 will receive 2 variables. But how ?

These variables will be put into the call stack memory. This is a linear, LIFO (Last in, First Out) type of allocation strategy.

Before calling function1(), the compiler will put var1 then var2 into the call stack, and increment the position of the call stack ceil. Then it will call function1(). function1() knows it must get 2 arguments, and so it finds them into the call stack.

What happens after function1() finishes ? Well, the call stack is decremented, and all variables into it are simply "disregarded", which is almost the same as "being erased".

So it's pretty clear that whatever you do to these variables during function1() is going to be lost for the calling program. If anything has to remain available to the calling program, it needs to be provided into a memory space that will survive the call stack decrement step.

Note that the logic is the same for any variable inside function1() : it will be unavailable to the calling function after function1() finishes. In essence, any result still stored into function1() memory space is "lost".

There are 2 ways to retrieve a usable result from a function.

The main one is to save the result of the function into a variable of the calling program/function. Consider this example :

int* foo3(size_t n) { return (int*) malloc(n); }

void callerFunction()
{
    int* p;
    p = foo3(100);  // p is still available after foo3 exits
}

The second, more complex, one is to provide as an argument a pointer to a structure which exists into the calling memory space.

Consider this example :

typedef struct { int* p; } myStruct;

void foo4(myStruct* s) { s->p = (int*) malloc(100); }

void callerFunction()
{
    myStruct s;
    foo4(&s); //p is now available, inside s
}

It is more complex to read, but also more powerful. In this example, myStruct contains a single pointer, but the structure could be a lot more complex. This open the perspective to offer myriad of variables as the result of a function, instead of being limited to basic types, as for the previous example with foo3().

So what happens when you know that your structure is in fact a simple basic type ? Well, you can just provide a pointer to it. And, by the way, pointer is itself a basic type. So if you want to get the result of a modified pointer, you can provide as an argument, a pointer to a pointer. And there we find foo1().

void foo1(int **p) {
    *p = (int *) malloc(100); // caller can get the memory
}
Cyan
  • 13,248
  • 8
  • 43
  • 78
2

Maybe it helps if we start with only one level of indirection.

consider this:

void foo1(int *p) {
              ^^
    //this p is local to the foo1 function
    //p contains the address of an int
    *p = 12;
    //now we dereference the pointer, so we set what p points to , to 12
 }

 void func(void) {
    int x;
        ^^
    //here is the x

    foo1(&x);
         ^^
    //now we find the location (address of) x, we copy that address
    //into the arguments for foo1()
    //foo1 sets our x int to 12

   }

Let's add one more indiretion:

void foo1(int **p) {
               ^^
    //this p is local to the foo1 function
    //p contains the address of a pointer to an int
    *p = NULL;
    //now we dereferenced the pointer, so we get an int*. We just
    //set it to NULL
 }

 void func(void) {
    int *x;
        ^^
    //here is the x.

    foo1(&x);
         ^^
    ///now we find the location (address of) x, we copy that address
    //into the arguments for foo1()
    //foo1() sets the x pointer to NULL. 

    }

In both cases we are able to manipulate the x variable inside func1(), since the location(address of) the x variable is passed into func1().

In the last case, we did *p = NULL;. Which would make x == NULL. We could have set it to something that malloc() returned: *p = malloc(100)

But if we alter the first case:

 void foo1(int *p) {
               ^^
    //this p is local to the foo1 function
    //p contains the address of an int
    p = NULL; 
    //now we just set the local `p` variable to NULL.
    //the caller will not see that, since `p` is just our own copy
    //of pointer.
 }

 void func(void) {
    int x;
       ^^
    //here is the x

    foo1(&x);
    //foo1 just set its own copy of the pointer we created by doing `&x` to NULL.
    //we will not see any changes here
  }

We just set p = NULL; in the last case here. If we used malloc instead:

void foo1(int *p) {
              ^^
    p = malloc(100); 
    //now we just set the local `p` variable to what malloc returns.
    //the caller will not see that, since `p` is just our own local copy
    //of the pointer.
    //When foo1() returns, noone has any way of knowing the location
    //of the memory buffer that malloc returned, so this memory is lost (a memory leak)
 }
nos
  • 223,662
  • 58
  • 417
  • 506
1

The problem with foo2 is that the p which is passed in is only modified inside the foo2 function. This is the same as :

void bar(int x)
{
   x = 42;
}

... 
    int a = 7;
    bar(a);
...

In the above code, a doesn't change because of the call to bar. Instead, a copy of a is passed to bar, and the copy is modified in bar.

The exact same thing happens in foo2. The memory is allocated, stored in p, which is a copy of the pointer passed in. When the code returns, the original pointer retains its original value.

By passing the address of a pointer (&ptr) to foo1, we can modify the ORIGINAL pointer, and thus pass the address of the allocation back to the caller of foo1.

Of course, when there is no reference back to the originally allocated memory, as is the case after a call to foo2, it is called a memory leak - generally considered a bad thing.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

Passing a pointer to value: A copy of the pointer(i.e. address of the value) is made in the function(on the stack frame). This allows you to modify the value.

Passing a pointer to a pointer: A copy of the pointer to a pointer(i.e. address of the pointer which in turn points to the value) is made in the function(on the stack frame). This allows you to modify the value as well as the pointer to this value.

The memory allocated using malloc, calloc, realloc and new resided on the heap which means that it exists even after a function returns(stack frame destroyed).

void foo2(int *p) {
    p = (int *) malloc(100);  // caller cannot get the memory
}

However, since the pointer p is lost after the function is returned, this memory cannot be accessed and will result in a leak.

HAL
  • 3,888
  • 3
  • 19
  • 28
0

As behaviour of all arguments is the same as local variables (they are passed by value), you can not modify pointer passed by value.

So in foo2() you allocate memory, but you can not use it outside the function, as you actually modify local variable.

The foo() function actually modifies the value pointed by **p, so pointer passed to function will be updated.

Alex
  • 9,891
  • 11
  • 53
  • 87