0

everybody! Really, I just want to understand what is going on with this references and pointers. Can you explain me, why in one case all is workking fine, but in another I receive nothing I will start with working case. So, there is a program (this is not mine):

#include <iostream>
#include <conio.h>

using namespace std;

struct node{
    double data;
    node *left;
    node *right;
};

node *tree = NULL;

void push(int a, node **t)
{
    if ((*t) == NULL)                   
    {
        (*t) = new node;                
        (*t)->data = a;                 
        (*t)->left = (*t)->right = NULL;       
        return;                         
    }

    if (a > (*t)->data) push(a, &(*t)->right); 
    else push(a, &(*t)->left);         
}

void print (node *t, int u)
{
    if (t == NULL) return;                  
    else 
    {
        print(t->left, ++u);                   
        for (int i=0; i<u; ++i) cout << "|";
        cout << t->data << endl;            
        u--;
    }
    print(t->right, ++u);                       
}
 
int main ()
{
    int n;                             
    int s;                              
    cout << "Enter the amount of elements  ";
    cin >> n;                           
 
    for (int i=0; i<n; ++i)
    {
        cout << "Enter the value  ";
        cin >> s;                       
 
        push(s, &tree);                 
    }

    cout << "Your binary tree\n";
    print(tree, 0);
    cin.ignore().get();
}

This is binary search tree made with struct, pointers and references. And it is work exactly fine But if i modify program in the way below it doesn't work. And i don't understand why, because

int *tree;
int **treePointer;
cout << (tree = *treePointer) <<endl; // Shows 1 i.e. true

Modified code:


#include <iostream>
#include <conio.h>

using namespace std;

struct node{
    double data;
    node *left;
    node *right;
};

node *tree = NULL;

void push(int a, node *t)
{
    if ((t) == NULL)                   
    {
        (t) = new node;                
        (t)->data = a;                 
        (t)->left = (t)->right = NULL;       
        return;                         
    }

    if (a > (t)->data) push(a, (t)->right); 
    else push(a, (t)->left);         
}

void print (node *t, int u)
{
    if (t == NULL) return;                  
    else 
    {
        print(t->left, ++u);                   
        for (int i=0; i<u; ++i) cout << "|";
        cout << t->data << endl;            
        u--;
    }
    print(t->right, ++u);                       
}
 
int main ()
{
    int n;                             
    int s;                              
    cout << "Enter the amount of elements  ";
    cin >> n;                           
 
    for (int i=0; i<n; ++i)
    {
        cout << "Enter the value  ";
        cin >> s;                       
 
        push(s, tree);                 
    }

    cout << "Your binary tree\n";
    print(tree, 0);
    cin.ignore().get();
}

As you see, all changes happen in push function argument. Why it is not working?

I am expecting that original program and modified will work the same

bababoah
  • 3
  • 3
  • Definitely, problem in recursion, when we call `push(a, (t)->right)`. Maybe there is should be `push(a, (&t)->right)`, but it says, that expression should be a pointer type, not node ** type But why `push(a, &(*t)->right)` is fine when our t has type node **t? – bababoah Oct 26 '22 at 16:11
  • When you pass a pointer to the function, the pointer data gets copied, and any changes in the body of the function, will not get reflected any where else. That is why the double pointer works, as it is equivalent to passing by reference. Have a look at https://stackoverflow.com/questions/4426474/is-passing-pointer-argument-pass-by-value-in-c#:~:text=Pointers%20are%20passed%20by%20value,point%20to%20the%20old%20object. – Atharva Dubey Oct 26 '22 at 16:21
  • @AtharvaDubey, just had a look, thank you. I knew that lifetime of all the arguments of the function exist just for function execution but got caught for this thing with pointers – bababoah Oct 26 '22 at 16:40
  • Main thing to note is that pointers too are passed by value, if you want to pass the pointer by reference, you would need pointer to pointer – Atharva Dubey Oct 26 '22 at 16:43

2 Answers2

2

This happens because of the following line in the modified code

(t) = new node;  

You are assigning memory to your pointer which is being created in a function call, a memory that will be lost after the function call.

Note that if you make changes to a member of a struct in a function call, the change will be reflected throughout because in that case, you will handle the member of the struct by reference.

But pointing the pointer to a new memory location created inside a function call will not propagate the changes. You need to pass the pointer by reference as well (thus pointer to a pointer).

Consider the following example -

#include <iostream>

typedef struct exampleStruct
{
    int a;
} exampleStruct;

void changeStruct(exampleStruct* S, int changedValue)
{
    S = new exampleStruct;
    S->a = changedValue;
    printf("Value of a inside Function = %d\n", S->a);
}

void changeStruct(exampleStruct** S, int changedValue)
{
    (*S) = new exampleStruct;
    (*S)->a = changedValue;
}

int main()
{
    exampleStruct* S = new exampleStruct;
    S->a = 100;
    printf("Value of a before calling function  = %d\n", S->a);
    changeStruct(S, 900);
    printf("Value of a after calling the function = %d\n", S->a);
    changeStruct(&S, 1300);
    printf("Value of a after calling 2nd function = %d\n", S->a);
}

The output is as follows -

Value of a before calling function  = 100
Value of a inside Function = 900
Value of a after calling the function = 100
Value of a after calling 2nd function = 1300

In the above example, similar to the modified code, the first function fails to propagate the changes, whereas the using pointer to the pointer does the trick

Atharva Dubey
  • 832
  • 1
  • 8
  • 25
0

In the modified code, when you do

(t) = new node;

you are setting the value of the local variable t to point to the new node. This value does not get put in your tree it only exists in the push function.

In the original

(*t) = new node;

sets the variable pointed to by t to the address of the new node. This means that the tree is modified.

Simon Fry
  • 141
  • 1
  • 6
  • Wow. This is make a sense. So, do I understand correctly, that in `print (node *t, int u)` we can use pointer, not a pointer-to-pointer, because we change nothing? And if our function `push(a, (t)->right)` did not imply to change any values, just read, we also could use just pointer, not pointer-to-pointer? – bababoah Oct 26 '22 at 16:29