为什么这些指针是相同的,同时指向一个对象的不同实例?

Why are these pointers the same, while referring to different instances of an object?

我正在调试为二叉搜索树创建的复制构造函数,我通过监视原始树和新创建的副本中节点的内存地址来执行此操作。一个节点由指向 Comparable 项(仅包含一个字符)的指针、该字符的出现次数以及指向其子节点(或 nullptr)的指针组成。

  struct Node {
    int count; // the number of occurences of the Comparable item (a char in this case)
    Comparable* item; // the Comparable item being tracked
    Node* leftChild;
    Node* rightChild;
  };

这是我的复制构造函数和助手:

BST::BST(const BST& tree)
{
  rootPtr = copy(tree.rootPtr);
}

BST::Node* BST::copy(Node* root)
{
  if (root == nullptr) {
    return nullptr;
  }

  Node* temp = new Node;
  Comparable* ptr = new Comparable;
  *ptr = *root->item;

  temp->item = ptr;
  temp->count = root->count;
  temp->rightChild = copy(root->rightChild);
  temp->leftChild = copy(root->leftChild);

  return temp;
}

我正在使用此函数将两棵树的数据以及它们在内存中的地址输出到控制台:

void BST::printInOrder(Node* root) const
{ 
  if (root->leftChild != nullptr) {
    printInOrder(root->leftChild);
  }

  cout << "&root: " << &root << " root: " << root << " :: " << *root->item << " " << root->count << endl;
  // example output: &root: 00EFF388 root: 0113E858 :: W 1

  if (root->rightChild != nullptr) {
    printInOrder(root->rightChild); 
  }
}

这是原始树(顶部)和复制构造函数构建的树(底部)的控制台输出:

  // original tree
    &root: 00EFF470     root: 01140760 :: ! 1
    &root: 00EFF558     root: 0113A018 :: H 1
    &root: 00EFF388     root: 0113E858 :: W 1
    &root: 00EFF2A0     root: 011406F0 :: d 1
    &root: 00EFF470     root: 01134940 :: e 1
    &root: 00EFF388     root: 01134A80 :: l 3
    &root: 00EFF2A0     root: 0113E7E8 :: o 2
    &root: 00EFF1B8     root: 01140680 :: r 1
    
  // copy of original tree
    &root: 00EFF470     root: 01140F90 :: ! 1
    &root: 00EFF558     root: 011407A0 :: H 1
    &root: 00EFF388     root: 01141390 :: W 1
    &root: 00EFF2A0     root: 01140C90 :: d 1
    &root: 00EFF470     root: 01140BE8 :: e 1
    &root: 00EFF388     root: 011410D0 :: l 3
    &root: 00EFF2A0     root: 01140E10 :: o 2
    &root: 00EFF1B8     root: 01140DD0 :: r 1

您会注意到,对于两棵树,第二列 (root:) 包含从第一棵树到第二棵树的一组完全不同的内存地址,这是有道理的,让我相信我的复制构造函数是正常工作,因为 Node* 指针指向内存中的不同地址(而这些地址包含相同的值)。

第一列(&root:)是我的困惑所在。我不明白为什么来自两棵树的节点的指针会被同一个指针指向(这更适合图表)。

//column 1:              //column 2:
//identical addresses    //different addresses
&root: 00EFF470          root: 01140760 :: ! 1
&root: 00EFF470          root: 01140F90 :: ! 1
         

任何关于在哪里进一步研究的见解或方向都会有所帮助,我当然是 C++ 的新手,哦,我正在使用 Visual Studio 2019,如果这对此有影响的话.

以下是您代码中的关键行:

void BST::printInOrder(Node* root) const
{ 

  cout << "&root: " ...

只检查这几行,只看这两行,然后问自己以下问题:

What is &root

将此视为一个突击测验。在阅读下面的答案之前,给自己五秒钟的时间来想出答案:

...

&root当然是printInOrder的“root”参数的地址。因此,当您两次调用此函数以打印两个不同的二叉树时,恰好在两个函数调用中参数恰好位于同一内存地址,在自动范围内。这就是为什么您每次都会看到相同的内存地址。

也许你想传递一个reference给根节点,作为这个参数?

换句话说:

void BST::printInOrder(Node *& root) const

&root是变量root的地址。变量 root 是一个指针,但该指针存在于堆栈中。

所以指针就像一张纸,上面写着街道地址。 root是一张纸,上面写着*root的地址。

&root那张纸。堆栈就像一条特殊的道路,您一直在其中构建和销毁“本地”变量存储。 root,那张纸,就在当地那条栈道上。 &root 是那张纸在本地栈“street”上的地址。

每次调用函数时,都会在堆栈上保留一些 space 用于其局部变量和参数。函数调用完成后,space 将被重用。

因为堆栈被重用,两个不同的函数将使用相同的内存——相同的地址——来存储不同的数据。当您调用一个函数时会发生这种情况,让它 return,然后调用另一个函数。