char指针不断意外地变化

时间:2017-08-19 16:03:40

标签: c++ pointers binary-search-tree

我正在使用二进制搜索树。 该程序应该按顺序存储树中的所有单词。

但每次调用insert函数时,' root'节点受影响。

标题

typedef char* CharPtr;

class BST
{

public:
    BST();
    ~BST();
    BST (const BST&);


void insert (CharPtr);
void printBST () const;

private:
    struct Node;
    typedef Node* NodePtr;

    struct Node{
        CharPtr word;
        int count;
        NodePtr left, right;
    };

    NodePtr root;

    // other private functions
    void PRVinsert (NodePtr&, CharPtr);
    //bool findNode (const NodePtr&, CharPtr)const;
    void inorderPrint (const NodePtr&)const;
};

我希望root->word在整个程序中保持不变,但它会不断变化。我做错了什么?

实施

// public function
void BST::insert (CharPtr currentWord){
    PRVinsert(root, currentWord);
}

// private function
void BST::PRVinsert (NodePtr& currentRoot, CharPtr w){

    if(currentRoot == NULL){
        NodePtr temp = new Node;
        temp -> word = w;
        temp -> left = NULL;
        temp -> right = NULL;
        temp -> count = 1;

        currentRoot = temp;
    }
    else{
        // compare two words
        int k = strcmp (currentRoot->word, w);

        if ( k > 0 )
            PRVinsert (currentRoot->left, w);
        else if ( k == 0 )
            currentRoot->count += 1;
        else
            PRVinsert (currentRoot->right, w);
    }

}

1 个答案:

答案 0 :(得分:0)

@SomeProgrammerDude已经解决了你的问题。您需要复制该字符串以进行存储。在我看来,真正突出的是你的struct Node没有构造函数,也没有析构函数来处理自己的存储需求。范围,构造函数和析构函数是C ++最重要的特性。

您应该考虑对BST :: Node的这些更改:

对于C ++ 98:

struct Node
{
    CharPtr word;
    int count;
    NodePtr left;  // <-- defining one variable per line is a good habit
    NodePtr right; //     to have and is a very common coding guideline.

    Node(const CharPtr w) : count(1)
    { 
        word = new char[strlen(w) + 1]; 
        strcpy(word, w); 
    }

    Node(const Node& other) 
       : word(NULL)
       , count(other.count)
       , left(NULL)
       , right(NULL)
    {
        if (other.left)
            left = new Node(*other.left);
        if (other.right)
            left = new Node(*other.left);
        if (other.word)
        {
            word = new char[strlen(other.word) + 1];
            strcpy(word, other.word);
        }
    }

    ~Node() 
    {
        delete left;   // calling delete NULL is fine, testing would only add extra noise.
        delete right;
        delete[] word; 
    }

private:
    Node& operator=(const Node& other); // avoid problems
};

对于C ++ 11,如果你的老师生活在21世纪:

struct Node
{
    CharPtr word{};
    int count{ 1 };
    NodePtr left{ nullptr };
    NodePtr right{ nullptr };

    Node(const CharPtr w)
    { 
        word = new char[strlen(w) + 1]; 
        strcpy(word, w); 
    }

    Node(const Node& other) : count(other.count)
    {
        if (other.left)
            left = new Node(*other.left);
        if (other.right)
            left = new Node(*other.left);
        if (other.word)
        {
            word = new char[strlen(other.word) + 1];
            strcpy(word, other.word);
        }
    }
    Node() = delete;
    Node(Node&& other) = default;
    Node& operator = (const Node&) = default;
    Node& operator = (Node&&) = default;

    ~Node() 
    {
        if (left) delete left;
        if (right) delete right;
        delete[] word; 
    }
};

现在,您必须记住,如果leftright不为空,您的析构函数将删除其下面的所有分支和叶子。立即更新这些指针,这样您就不会意外删除在树中移动内容时要保留的分支。

这会改变你的Insert()函数:

void BST::PRVinsert (NodePtr& currentRoot, CharPtr w)
{
    if (currentRoot == NULL)
    {
        currentRoot = new Node(w);
        return; 
    }

    // compare two words
    int k = strcmp (currentRoot->word, w);

    if ( k > 0 )
        PRVinsert (currentRoot->left, w);
    else if ( k == 0 )
        currentRoot->count += 1;   // <-- this is the line that was being hit all the time
                                   // when node->word was not allocated correctly.
    else
        PRVinsert (currentRoot->right, w);
}

并大大简化了BST的复制构造函数和析构函数。

BST::BST(const BST& other) : root(NULL)
{
    if (other.root)
        root = new Node(*other.root);
}

BST::~BST()
{
    delete root;
}