-1

I have this code:

void alloc2(int** p) {
   *p = (int*)malloc(sizeof(int));
   **p = 10;
}

void alloc1(int* p) {
   p = (int*)malloc(sizeof(int));
   *p = 10;
}

int main(){
   int *p;
   alloc1(p);
   //printf("%d ",*p);//value is undefined
   alloc2(&p);
   printf("%d ",*p);//will print 10
   free(p);
   return 0;
}

So, I understand that alloc1 just makes a local copy so it's not effecting outside the function the pointer which is given as a parameter.

But what is happening with alloc2?

tl;dr;

And why this alloc1(&p); won't work?

Update

I think i answered my question. The crucial thing is that & makes you a pointer and then a was built to a double pointer bei dereferencing once. Then the double pointer points to the address given be malloc. Finally the address was filled with 10.

And alloc1(&p); would work, but you couldn't derefence the double pointer since it takes a single pointer.

Thanks to all of you

int80
  • 21
  • 6
  • "Double pointers" *are* normal pointers. They're just pointers that point to other pointers. Just like a "single pointer" is a pointer to points to something that's not a pointer. – user253751 Jan 17 '16 at 00:43

2 Answers2

2

It didn't become a double pointer, in alloc2() you are passing a pointer containing the address of main()'s p. When you dereference it you are actually modifying the address stored in main()'s p. And that's why it's working.

Since there is no pass by reference in , the only way you can modify a parameter inside a function is by passing a pointer with it's address, for example if you have to pass an integer to a function and the function needs to modify it then you make a pointer using the address of & operator and pass that pointer to the function, example

void
modify(int *pointer)
{
    *pointer += 1;
}

int
main(void)
{
    int value;
    value = 0;

    modify(&value);
    printf("%d\n", value);

    modify(&value);
    printf("%d\n", value);
}

would output

1
2

A double pointer is a pointer to a pointer, so you are making a pointer from p in main() which stores the address of p in main(), the pointer itself is stored somewhere, so you are passing the address where the pointer is stored and hence you can modify it's contents from within alloc2().

Note: It's bad style to cast the return valud of malloc(), read more about it here.

Community
  • 1
  • 1
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • so what I don't understand are those lines: `*p = (int*)malloc(sizeof(int));` and `**p = 10;` ... this must be dereferencing? – int80 Jan 17 '16 at 01:34
1

It would be clearer if you gave the variables in different functions different names. Since you have multiple variables and arguments named p, and they are distinct from each other, it is easy to confuse yourself.

void alloc2(int** pa2)
{
     *pa2 = (int*)malloc(sizeof(int));
     **pa2 = 10;
}

void alloc1(int* pa1) 
{
    pa1 = (int*)malloc(sizeof(int));
    *pa1 = 10;
}

int main()
{
    int *p = 0;
    alloc1(p);
    //printf("%d ",*p);//value is undefined
    alloc2(&p);
    printf("%d ",*p);//will print 10
    free(p);
    return 0;
}

Apart from renaming the arguments of functions, I've also initialised p in main() to zero (the NULL pointer). You had it uninitialised, which means that even accessing its value (to pass it to alloc1()) gives undefined behaviour.

With p being NULL, alloc1() also receives the NULL pointer as the value of pa1. This is a local copy of the value of p from main(). The malloc() call then changes the value of pa1 (and has no effect on p in main(), since it is a different variable). The statement *pa1 = 10 sets the malloced int to be 10. Since pa1 is local to alloc1() it ceases to exist when alloc1() returns. The memory returned by malloc() is not free()d though (pa1 ceases to exist, but what it points to doesn't) so the result is a memory leak. When control passes back to main(), the value of p is still zero (NULL).

The call of alloc2() is different, since main() passes the address of p. That is the value of pa2 in alloc2(). The *pa2 = (int *)malloc(sizeof(int)) statement does change the value of p in main() - to be the value returned by malloc(). The statement **pa2 = 10 then changes that dynamically allocated int to be 10.

Note also that the (int *) on the result of malloc() is unnecessary in C. If you need it, it means one of

  1. You have not done #include <stdlib.h>. The type conversion forces the code to compile, but any usage of the int - strictly speaking - gives undefined behaviour. If this is the case, remove the int * and add #include <stdlib.h>.
  2. You are compiling your C code using a C++ compiler.
Peter
  • 35,646
  • 4
  • 32
  • 74
  • thanks peter, so I understand the scope thing, pass by value, pass by reference. I dont understand `*pa2 = (int *)malloc(sizeof(int))` why is this not: `pa2 = (int *)malloc(sizeof(int))` (without `*`). Because with a `*` you are actually dereferencing the address where it points to. And as you can see `p` points to NULL... – int80 Jan 17 '16 at 01:19
  • @int80 `p` has the value `0`, but what is passed to `alloc2()` is `&p`, which is a pointer to `p`. So the parameter `pa2` is a pointer to `p`, not a NULL pointer. Therefore, when `pa2` is dereferenced with `*`, you are assigning a value to `p`. – Marc Khadpe Jan 17 '16 at 02:43
  • so, with the first dereferncing you actually store the address given by malloc into `pa2` instead store a commen value? Hence you can store a value by dereferencing double? I may understand now :) – int80 Jan 17 '16 at 14:15