C++ 从函数返回指针是如何工作的?

C++ 从函数返回指针是如何工作的?,c++,pointers,C++,Pointers,考虑以下代码段: #include <iostream> #include <queue> struct node { int key; node *l; node *r; node(int key) :key(key), l(nullptr), r(nullptr) { } }; struct bst { node *root; bst() :root(nullptr) { }

考虑以下代码段:

#include <iostream>
#include <queue>

struct node {
    int key;
    node *l;
    node *r;

    node(int key)
        :key(key), l(nullptr), r(nullptr) {
    }
};

struct bst {
    node *root;

    bst() :root(nullptr) {

    }

    node* find(int key) {
        return find(root, key); 
    }

    node* find(node *root, int key) {
        if (!root) {
            return nullptr;
        } else {
            if (root->key < key) {
                return find(root->l, key);
            }
            else if (root->key > key) {
                return find(root->r, key);
            } else {
                return root;
            }
        }
    }

    void insert(int key) {
        insert(root, key);
    }

    void insert(node *&root, int key) {
        if (!root) {
            root = new node(key);
        } else {
            if (root->key < key) {
                insert(root->r, key);
            } else if (root->key > key) {
                insert(root->l, key);
            } else {
                return;
            }
        }
    }

    void print_by_level(std::ostream &o) {
        if (!root) {
            o << "(empty)";
            return;
        }
        std::queue<node*> q;
        int curr_lv = 1;
        int next_lv = 0;
        q.push(root);
        while (!q.empty()) {
            auto p = q.front();
            q.pop();
            curr_lv--;
            o << p->key << ' ';
            if (p->l) {
                q.push(p->l);
                next_lv++;
            }
            if (p->r) {
                q.push(p->r);
                next_lv++;
            }
            if (curr_lv == 0) {
                o << '\n';
                curr_lv = next_lv;
                next_lv = 0;
            }
        }
        o << '\n';
    }

};

int main() {
    bst t;
    t.insert(5);
    t.insert(10);
    t.insert(15);
    t.print_by_level(std::cout);

    // return pointer to 5 which is root
    node *p = t.find(5);
    // modify it, ok
    p->key = 100;
    t.print_by_level(std::cout);

    // now try to delete or change where p is pointing to
    delete p;
    p = nullptr;
    // then it's not happy :(
    t.print_by_level(std::cout);

    return 0;
}
现在尝试更改
p
指向并返回
节点*&
:(请原谅我的恶意攻击
nullp
:())

#包括
#包括
结构节点{
int键;
节点*l;
节点*r;
节点(int键)
:key(key)、l(nullptr)、r(nullptr){
}
};
结构bst{
节点*根;
节点*nullp;
bst():根(nullptr),nullp(nullptr){
}
节点*&查找(int键){
返回find(root,key);
}
节点*&查找(节点*根,int键){
如果(!root){
返回nullp;
}否则{
如果(根->键<键){
返回查找(根->l,键);
}
否则如果(根->键>键){
返回find(root->r,key);
}否则{
返回根;
}
}
}
无效插入(整数键){
插入(根,键);
}
无效插入(节点*&根,int键){
如果(!root){
根=新节点(键);
}否则{
如果(根->键<键){
插入(根->r,键);
}否则如果(根->键>键){
插入(根->l,键);
}否则{
返回;
}
}
}
/**
*p q
*         / \             / \
*q x3=>x1 p
*      /  \                 / \
*x1x2x2x3
*/
无效旋转带左子节点(节点*&p){
节点*q=p->l;
p->l=q->r;
q->r=p;
p=q;
}
按级别作废打印(标准::ostream&o){
如果(!root){
o(l);
next_lv++;
}
如果(p->r){
q、 推动(p->r);
next_lv++;
}
如果(当前值=0){

o在
main
中,当您
delete p
时,实际上是在删除
t
对象中的
root
指针!不要这样做,否则您将有未定义的行为,这就是您在此处遇到的情况


返回指针时,返回指针的副本,两个指针将指向同一个对象。如果随后
删除其中一个指针,另一个指针将指向已删除的对象。

[这不一定是答案,而是带有代码的注释]

代码可能存在变量阴影,成员“root”与函数参数“root”明显冲突

有助于避免此类问题的常见做法是在成员和其他特殊情况前加前缀,例如“m_u”表示“成员”,“s_u”表示静态,“g_u”表示“全局”。不要将其与可怕的匈牙利语混淆,至少

struct bst{
节点*m_根;
节点*m_nullp;
bst():m_root(nullptr),m_nullp(nullptr){
}
节点*&查找(int键){
返回find(m_root,key);
}
节点*&查找(节点*根,int键){
如果(!root){//肯定表示参数
返回nullp;
}否则{
如果(根->键<键){
返回查找(根->l,键);
}
否则如果(根->键>键){
返回find(root->r,key);
}否则{
返回根;
}
}
}
无效插入(整数键){
插入(m_根,键);
}

指针指向内存位置。取消引用指针可以访问它所指向的内容。100个不同的指针可以指向同一个位置,所以复制或原始并不重要。它返回指向找到的节点的指针*。如果需要,您必须复制它。
我希望p从find()返回是什么意思根是否为
p==root
应该为true,但是
&p==&root
将为false。当使用该代码图片时,当您希望
t->查找(2)
时,它还应该返回根节点ptr。您应该检查正确的值
否则返回null ptr;
但它应该从
t.print\u按级别打印(空)(std::cout);
对吗?@Chan未定义的行为,根据其定义,是未定义的。它甚至可能是。非常感谢。明白了,但是如果我更改
p
指向的位置而不是删除,它还会产生“未定义的行为”吗?Chan否,因为您只是更改指针
p
,而不是指针
t.root
。因此,如果我想要实际的
t.root
,我是否应该返回
node*&
?很好,我正在尝试快速键入演示,因此变量
root
意外出现。谢谢。
int main() {
    bst t;
    t.insert(5);
    t.insert(10);
    t.insert(15);
    t.print_by_level(std::cout);

    // return pointer to 5 which is root
    node *p = t.find(5);
    // modify it, ok
    p->key = 100;
    t.print_by_level(std::cout);

    delete t.root;
    t.root = nullptr;
    // ok happy now
    t.print_by_level(std::cout);
    return 0;
}
#include <iostream>
#include <queue>

struct node {
    int key;
    node *l;
    node *r;

    node(int key)
        :key(key), l(nullptr), r(nullptr) {
    }
};

struct bst {
    node *root;
    node *nullp;

    bst() :root(nullptr), nullp(nullptr) {

    }

    node*& find(int key) {
        return find(root, key); 
    }

    node*& find(node *root, int key) {
        if (!root) {
            return nullp;
        } else {
            if (root->key < key) {
                return find(root->l, key);
            }
            else if (root->key > key) {
                return find(root->r, key);
            } else {
                return root;
            }
        }
    }

    void insert(int key) {
        insert(root, key);
    }

    void insert(node *&root, int key) {
        if (!root) {
            root = new node(key);
        } else {
            if (root->key < key) {
                insert(root->r, key);
            } else if (root->key > key) {
                insert(root->l, key);
            } else {
                return;
            }
        }
    }

    /**
     *          p               q
     *         / \             / \
     *        q   x3     =>  x1   p
     *      /  \                 / \
     *     x1   x2              x2  x3
     */
    void rotate_w_left_child(node *&p) {
        node *q = p->l;
        p->l = q->r;
        q->r = p;
        p = q;
    }

    void print_by_level(std::ostream &o) {
        if (!root) {
            o << "(empty)";
            return;
        }
        std::queue<node*> q;
        int curr_lv = 1;
        int next_lv = 0;
        q.push(root);
        while (!q.empty()) {
            auto p = q.front();
            q.pop();
            curr_lv--;
            o << p->key << ' ';
            if (p->l) {
                q.push(p->l);
                next_lv++;
            }
            if (p->r) {
                q.push(p->r);
                next_lv++;
            }
            if (curr_lv == 0) {
                o << '\n';
                curr_lv = next_lv;
                next_lv = 0;
            }
        }
        o << '\n';
    }

};

int main() {
    bst t;
    t.insert(5);
    t.insert(4);
    t.insert(1);
    t.print_by_level(std::cout);
    node *p = t.find(5);
    // using root, happy
    // t.rotate_w_left_child(t.root);
    // t.print_by_level(std::cout);

    // using p, not happy :(
    t.rotate_w_left_child(p);
    t.print_by_level(std::cout);
    return 0;
}
struct bst {
    node *m_root;
    node *m_nullp;

    bst() : m_root(nullptr), m_nullp(nullptr) {
    }

    node*& find(int key) {
        return find(m_root, key); 
    }

    node*& find(node *root, int key) {
        if (!root) { // definitely means the parameter
            return nullp;
        } else {
            if (root->key < key) {
                return find(root->l, key);
            }
            else if (root->key > key) {
                return find(root->r, key);
            } else {
                return root;
            }
        }
    }

    void insert(int key) {
        insert(m_root, key);
    }