0

I was iterating a tree data structure which has a pointer to its root as follows-

struct node *root;

when I have to pass reference of this root as a parameter to a function.... I have to pass it like-

calcHeight(&root);
-
-
-
//somewhere

int calcHeight(struct node **root)      // function defination is this

My question is- why do we need to pass "root" pointer as &root? can't we just pass root like--

struct node *root;
calcHeight(root);
int calcHeight(struct node *root);

// EDIT

void someFunct(int *arr){
    printf("arr2 inside someFunct is %d\n",arr[2]);
    arr[2]=30;
}

int main()
{
    int *arr=(int*)calloc(10,sizeof(int));
    printf("arr[2] is %d\n",arr[2]);

    someFunct(arr);
    printf("arr[2] finally is %d\n",arr[2]);
    return 0;
}

In this case arr in main function is modified even when I'm not passing the address of arr. I'm getting the fact that for structures and single value vars we HAVE to pass the address like someFunct(&var) but this is not necessary for arrays? for arrays we write someFunct(arr)
But I'm not getting the reason behind this?

meg
  • 25
  • 5
  • 1
    Does this answer your question? [What are the differences between a pointer variable and a reference variable in C++?](https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in) – zerocukor287 Dec 05 '21 at 12:10

3 Answers3

3

struct node * is a pointer to a struct node.
struct node ** is a pointer to a pointer to a struct node.

The reason for passing in a struct node ** could be that the function needs to modify what the struct node * is actually pointing at - which seems odd for a function named calcHeight. Had it been freeNode it could have made sense. Example:

void freeNode(struct node **headp) {
    free(*headp);
    *headp = NULL; // make the struct node * passed in point at NULL
}

Demo

Another reason could be to make the interface consistent so that one always needs to supply a struct node ** to all functions in the functions supporting struct nodes - not only those actually needing to change what the struct node * is pointing at.


Regarding the added // EDIT part:

In this scenario there is no reason to send in a pointer-to-pointer. If you do not need to change the actual pointer, you only need to send in the value of the pointer.

Example memory layout:

Address    What's stored there
+-----+
|  +0 |     uint64_t   ui1 = 1     <--+
+-----+                               |
|  +8 |     uint64_t   ui2 = 2        |
+-----+                               |
| +16 |     uint64_t*  p   = &ui1  ---+
+-----+

Now, if a function only need an uint64_t value, you can send in ui1, ui2 or *p to that function.

void someFunc(uint64_t val) { ++val; ... }

The changes this function makes to val are not visible to the caller of the function.

If a function is supposed to be able to make changes that are visible to the caller of the function, send in a pointer:

void someFunc(uint64_t *valp) { *valp = 10; }

Calling it with someFunc(&ui1); or someFunc(p); will change ui1 and assign 10 to it.

If you have a pointer and want to change what it's actually pointing at, which is what your original question was asking, you would need to send in a pointer to that pointer:

void someFunc(uint64_t **valpp) { *valpp = &ui2 }`

If you call that with someFunc(&p) (where p is currently pointing at ui1) you will find that after the function call, p will point at ui2:

+-----+
|  +0 |     uint64_t   ui1 = 1
+-----+
|  +8 |     uint64_t   ui2 = 2     <--+
+-----+                               |
| +16 |     uint64_t*  p   = &ui2  ---+
+-----+
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • So basically whenever I have to modify the value then I have to pass the address of the pointer- someFunct(struct node &root) ? and if I just want to access it then passing the pointer is enough- someOtherFunct(struct node root)? – meg Dec 05 '21 at 17:11
  • @meg That would be `someFunct(&root);` and `someFunct(root);`, but yes, that's usually how it is. Most libraries do not set the pointer to NULL in the "free" function, but doing so is also pretty common. and in that case you need to pass a `**` – Ted Lyngmo Dec 05 '21 at 17:14
  • Why is it so? if we can access the value through someFunct(root) then why can't we modify it? – meg Dec 05 '21 at 17:19
  • @meg With a `struct node *` you can modify what it's pointing at but not the actual pointer that you used to call the function. You need the address of that variable to be able to change that variable. If you check the demo and change the function to not take a `**` but a `*` and set it to `NULL` in the function, you will not see the effect outside the function. – Ted Lyngmo Dec 05 '21 at 17:20
  • Okay! so basically a copy of that pointer var is made... actual var is never modified? – meg Dec 05 '21 at 17:25
  • @meg Yes, a copy of the value the pointer holds is sent into the function unless you take the address of the variable instead. – Ted Lyngmo Dec 05 '21 at 17:29
  • If I have to pass a integer pointer and modify its value then I dont pass the address- I simply write someFunct(ptr) instead of someFunct(&ptr) where ptr is - int *ptr=(int*)calloc(1,sizeof(int)) ?why is it so? Do we have to pass the address only for structure pointers? – meg Dec 06 '21 at 03:16
  • @meg If yu have an int pointer and would like it to point somewhere else you need to send in it's address, an int** – Ted Lyngmo Dec 06 '21 at 07:11
  • but it works without that also...someFunct(ptr) -like this? – meg Dec 08 '21 at 02:40
  • @meg No, if `ptr` is an `int*` and you want to change what it's pointing at, you must do `someFunc(&ptr)` (and `someFunc` must then take an `int**`). [Demo](https://godbolt.org/z/ov1shn1bx) – Ted Lyngmo Dec 08 '21 at 08:09
  • Okay, thanks for the demo! But what about arrays? I never pass address of array I always do ` someFunct(arr) ` I will edit the question and add the code for array part... for more clarity on what I'm trying to ask.... – meg Dec 08 '21 at 11:53
  • @meg Don't edit this question now. I think posting a new question is more appropriate. Arrays decay into pointers to the first element when sent into functions. The same applies to them. If you have a pointer to an array and want that pointer to point at another array, you need to send in the pointer to that pointer. Nothing different. – Ted Lyngmo Dec 08 '21 at 11:55
  • But the code works without sending the address also?No, I just want to modify the array! I edited the question and gave an example on what I'm trying to ask – meg Dec 08 '21 at 12:06
  • @meg I added some ascii drawings to try to visualize it a bit. I'm not a great artist though :-) – Ted Lyngmo Dec 08 '21 at 12:41
  • No....It was great ^_^Thank you so much for your efforts! Its crystal clear now! – meg Dec 08 '21 at 16:21
  • @meg Cool! You're welcome! – Ted Lyngmo Dec 08 '21 at 17:48
0

Because in calcHeight you're passing your argument by value. If you want to modify the pointed value by root you need to pass the adress of the pointer.

tony_merguez
  • 307
  • 2
  • 11
0

First one is a pointer to node which is a structure.

struct node *root;

defines root as a variable which can store the address of a node.

Second one is a pointer to a pointer to node which is a structure.

struct node **root;

defines root as variable which can store address of another variable which has the address of a node.

why do we need to pass "root" pointer as &root?

calcHeight(&root);

C passes arguments by value, not by reference. so, you have to pass the address of root to modify the value of root.

vegan_meat
  • 878
  • 4
  • 10