【问题标题】:Passing a Pointer into a Function and Modifying it将指针传递给函数并修改它
【发布时间】:2014-03-01 11:12:11
【问题描述】:

stackoverflow 和 C/C++ 的新手。我正在通过实现二叉树并有一个简单的问题。假设我有以下内容:

struct Node {
    int data;
    Node* right_child;
    Node* left_child;
};

void addNode(Node* tree, int new_data){
    if(tree == NULL){
        Node* new_tree = new Node;
        new_tree->data = new_data;
        new_tree->right_child = NULL;
        new_tree->left_child = NULL;
        tree = new_tree;
    }
}

int main(){
    Node* tree = new Node;
    tree = NULL;
    addNode(tree, 3);
    cout << tree->data << endl; //CRASH
}

很简单吧。它会崩溃,因为树仍然是 NULL,即使在从 addNode 返回之后。我试图理解的是为什么一旦调用 addNode 就不会更新它。当然,使用并更新了指针的副本,但它不应该仍然保持相同的地址吗?因此,仍然更新原始内存地址并返回。或者新指针是否出于某种原因指向不同的位置?我对正在发生的事情感到困惑。任何帮助都会很棒。

另外,我只是在网站上编写了该代码 - 抱歉,如果有小错误,并没有实际运行它。

谢谢。

【问题讨论】:

  • 为什么tree在初始化后就设置为NULL?

标签: c++ function pointers


【解决方案1】:

有几个问题,

首先,您有一个指针addNode 的本地副本,并且您不是取消引用它以作用于它指向的东西,而是直接作用于本地指针本身。在函数内部创建的newed Node 将永远丢失。

您可以通过引用传递指针来解决该问题。这不需要对您的代码进行任何其他修改:

void addNode(Node*& tree, int new_data)

其次,正如您所指出的,您正在取消引用 main 中的 NULL 指针。这只是未定义的行为 (UB)。可能发生的事情之一是崩溃。但是代码也可以静默运行而不会崩溃。重要的事实是,它是UB,程序不能依赖。

注意 1:如果您想初始化 Nodes 以使数据成员初始化为零,请使用 值初始化

Node* tree = new Node();

注意 2:使用原始 newed 指针时要非常小心。您的代码中已经有 one two 资源泄漏。最好使用最合适的智能指针类型。

【讨论】:

    【解决方案2】:

    如果你想在你的主函数中保留变化(对于指针或非指针变量),安全的方法是通过引用传递它,因为引用变量只能初始化一次

    即:

    void addNode(Node*& tree, int new_data)
    {
       Node* tree_1;
    
       tree = &tree_1 //this can't be done
    }
    
    void addNode(Node** tree, int new_data)
    {
       Node* tree_1;
    
       tree = &tree_1 //this can be done
    }
    

    所以最安全的方法是通过引用,我的意思是void addNode(Node*&amp; tree, int new_data)

    【讨论】:

    • 引用确实只能初始化一次,但其他一切也是如此。无论如何,标有“这不能做”的那一行实际上是可以做到的。正如我的回答中所解释的那样,通过引用传递是修复 OP 的需要。
    • 你能编译一个示例代码吗?对于第一个 addNode 函数,编译器说 Error '=' : cannot convert from 'Node **' to 'Node *'
    • 你能不能和我的一样运行 void addNode(Node*& tree, int new_data) { Node* tree_1; tree = &tree_1 //这不行 }
    • 拜托,我的意思是 f = &tmp;不是 f = tmp;
    • 啊,好吧,我没看到。它实际上没有任何意义,与引用无关。您正在尝试将 Node** 分配给 Node*
    【解决方案3】:

    因此,您将指针传递给 addNode 中的树

    void addNode(Node* tree, int new_data)
    

    声明

    tree = new_tree;
    

    只会是本地的,您不会更改传递的指针指向的内容,因为树是指针的副本。

    比较

    void foo(int n) {  n = 1; }   // local, n is a copy
    void foo(int* n) { *n = 1; }  // change the original variabel
    

    为了改变树指向你需要传递指针的地址

    void addNode(Node** tree, int new_data)
    {
    ...
       *tree = new Node;
    ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      • 2014-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多