0

in this code, I think it must do deep copy because I'm passing pointers, but it doesn't. I think it must print 3, but print 0. what should I do to solve this? i want to have a deep copy instead of a shallow copy.

 struct node{
    int number = 0;
    struct node* right_child = NULL;
    struct node* left_child = NULL;
  };

void test(struct node* node1 , struct node* node2){
    node1 = node2;
}

int main(){
    struct node* a1 = new struct node;
    struct node* a2 = new struct node;
    a2->number = 3;
    test(a1 , a2);
    cout << a1->number;
}
  • how can i have deep copy? i need deep copy in this case – Alireza Arbabi Dec 02 '21 at 22:17
  • See Julien's answer – Rafaelplayerxd YT Dec 02 '21 at 22:18
  • You don't even have a shallow copy, just copies of the pointers, which does nothing. Did you intend `node1->number = node2->number;`? – BoP Dec 02 '21 at 22:31
  • 1
    Just implement a `clone` method that does the deep copy, recursion can help. – Quimby Dec 02 '21 at 22:31
  • 2
    Nothing has been copied except that address in `node2` to `node1`, and since `node1` and `node2`, are local variables scoped by `test`, this has no effect outside `test`. Effectively `test` does absolutely nothing. – user4581301 Dec 02 '21 at 22:32
  • Side note: all the `struct` except the first one are not necessary. – Ranoiaetep Dec 02 '21 at 22:33
  • Note that a pointer is just another variable, except rather than containing a number or a letter, it contains an address. When you use a pointer as a function parameter, you pass the object the pointer points at by reference, but the pointer itself is passed by value. If you need to change where a pointer points inside a function, you need to pass the pointer by reference, too. – user4581301 Dec 02 '21 at 22:35
  • You look to be implementing a link list. It is unclear what test() is trying to do. Are these two nodes in one list or two lists each with one node? Is test() making two items in one list have the same value or do you wish to copy a list? – William J Bagshaw Dec 03 '21 at 01:20

2 Answers2

0

The simple C-ish way: We ad a function that recursively clones the nodes

#include <iostream>

struct node{
    int number = 0;
    node* right_child = nullptr; // nullptr safer than NULL
    node* left_child = nullptr;

};

node * clone(const node * src){
    if (src) { // there is a node. Copy it.
        return new node{src->number,
                        clone(src->right_child), // clone right
                        clone(src->left_child)}; // clone left
    }
    else { // no node. Nothing to do and end the branch
        return nullptr;
    }
}

void test(node*& node1, // reference to pointer
          node* node2){
    delete node1; // Free storage currently used by node1
                  // But what of the nodes that could be in its tree? 
                  // Think on this. Ask another question if necessary.
                  // this is where the simple way starts to fall down
    node1 = clone(node2);
}

int main(){
    struct node* a1 = new node; // wasted memory. We're about to replace it.

    // need a more complicated tree to prove deep copy works
    struct node* a2 = new node{3,
                               new node{4, nullptr, nullptr}, // a right node
                               nullptr}; // no left node
    // a2->number = 3; done above now
    test(a1 , a2);
    std::cout << a1->number << ' '
              << a1->right_child->number;

    delete a1; // clean up
    delete a2;
}

More complicated canonical C++ way using The Rule Of Three and The Copy and Swap Idiom

#include <iostream>
#include <algorithm> // for std::swap

struct node{
    int number = 0;
    node* right_child = nullptr; // nullptr safer than NULL
    node* left_child = nullptr;

    static node * clone(node * src)
    {
        if (src)
        {
            return new node(*src);
        }
        return nullptr;
    }
    // generic constructor
    node(int number = 0,
         node* right_child = nullptr,
         node* left_child = nullptr):
             number(number),
             right_child(right_child),
             left_child(left_child)
    {

    }
    //copy constructor
    node (const node & src):
          number(src.number),
          right_child(clone(src.right_child)),
          left_child(clone(src.left_child))
    {

    }
    // assignment operator via copy and swap.
    node & operator=(node src)
    {
        std::swap(number, src.number);
        std::swap(right_child, src.right_child);
        std::swap(left_child, src.left_child);
        return *this;
    }
    // destructor
    ~node()
    {
        delete right_child;
        delete left_child;
    }
};

void test(node* node1,
          node* node2){
    *node1 = *node2; // now, thanks to all of the infrastructure above, we can 
                     // assign nodes with the dumb old = operator. All we have to do 
                     // is dereference the pointers.
}

int main(){
    struct node* a1 = new node; // wasted memory. We're about to replace it.

    // need a more complicated tree to prove deep copy works
    struct node* a2 = new node{3,
                               new node{4, nullptr, nullptr}, // a right node
                               nullptr}; // no left node
    // a2->number = 3; done above now
    test(a1 , a2);
    std::cout << a1->number << ' '
              << a1->right_child->number;

    delete a1; // clean up
    delete a2;
}

All of the nodes are now self-managing.

But, my opinion, the nodes should be kept as dumb as they are in the simple example. They shouldn't need to know about the tree at all. Knowledge of the tree should be in a Tree class that uses the nodes as simple containers. The Tree class should do all of the management of the nodes--creating, copying, cloning, deleting--because only it knows everything necessary to represent the tree. The users of the tree shouldn't even know nodes exist. They put data into the tree, take data out of the tree, and observe the tree without caring how the tree works and being able to so something stupid like

delete a_node;

and blow the crap out of data the tree isn't done with yet.

The Tree class preferably works iteratively rather than recursively so that the trees can be arbitrarily sized. Unless you're really careful recursing through a large tree to clone it, delete it, display it, or pretty much anything else you do with a tree runs the risk of exhausting automatic storage and causing what's typically called a Stack Overflow.

user4581301
  • 33,082
  • 7
  • 33
  • 54
-1

just use

void test(struct node *node1, struct node *node2) { *node1 = *node2; }

instead of

void test(struct node *node1, struct node *node2) { node1 = node2; }

and it will print 3.

This is because...

when you do node1 = node2; int the test1, you assign the pointer itself, not the structure pointed to by the pointer.When the function ends, the parameters node1 and node2 will be destroyed, so you have done nothing...

  • This is not a deep copy and will result in two trees pointing at the exact same nodes. Sooner or later one tree will be edited and you'll see the same change in the "Copy" or the clean-up code to free the tree's nodes will free the nodes in BOTH trees leaving the program with a tree pointing to invalid nodes. – user4581301 Dec 06 '21 at 19:36