2009-06-14 8 views
2

バイナリツリーをテストするプログラムを作成しました。プログラムを実行すると、プログラムがクラッシュするようです(btree.exeが機能しなくなり、Windowsが解決策をチェックしています...)。戻り値0の後のsegfault。

デバッガで実行し、break_tree()の原因と思われる関数にブレークポイントを設定すると、期待通りに実行されてメイン関数に返されたように見えます。 Mainはプログラムから返されますが、カーソルはdestroy_tree()にジャンプし、カーソルは自己内部で反復してループします。

最小コードサンプルは以下のとおりですので、即座に実行できます。私のコンパイラはMinGWで、私のデバッガはgdbです(私はCode :: Blocksを使用しています)。

#include <iostream> 

using namespace std; 

struct node 
{ 
    int key_value; 
    node *left; 
    node *right; 
}; 

class Btree 
{ 
public: 
    Btree(); 
    ~Btree(); 
    void insert(int key); 
    void destroy_tree(); 

private: 
    node *root; 

    void destroy_tree(node *leaf); 
    void insert(int key, node *leaf); 
}; 

Btree::Btree() 
{ 
    root = NULL; 
} 

Btree::~Btree() 
{ 
    destroy_tree(); 
} 

void Btree::destroy_tree() 
{ 
    destroy_tree(root); 

    cout<<"tree destroyed\n"<<endl; 
} 

void Btree::destroy_tree(node *leaf) 
{ 
    if(leaf!=NULL) 
    { 
    destroy_tree(leaf->left); 
    destroy_tree(leaf->right); 
    delete leaf; 
    } 
} 

void Btree::insert(int key, node *leaf) 
{ 
    if(key < leaf->key_value) 
    { 
     if(leaf->left!=NULL) 
      insert(key, leaf->left); 
     else 
     { 
      leaf->left = new node; 

      leaf->left->key_value = key; 
      leaf->left->left = NULL; 
      leaf->left->right = NULL; 
     } 
    } 
    else if (key >= leaf->key_value) 
    { 
     if(leaf->right!=NULL) 
      insert(key, leaf->right); 
     else 
     { 
      leaf->right = new node; 

      leaf->right->key_value = key; 
      leaf->right->left = NULL; 
      leaf->right->right = NULL; 
     } 
    } 
} 

void Btree::insert(int key) 
{ 
    if(root!=NULL) 
    { 
     insert(key, root); 
    } 
    else 
    { 
     root = new node; 

     root->key_value = key; 
     root->left = NULL; 
     root->right = NULL; 
    } 
} 

int main() 
{ 
    Btree tree; 
    int i; 

    tree.insert(1); 

    tree.destroy_tree(); 

    return 0; 
} 

これ以外にも、これらの問題をデバッグするために、Code :: Blocks組み込みデバッガからDDDに切り替える予定です。私は、DDDがポインタのアドレスを表示するのではなく、視覚的にオブジェクトへのポインタを表示できると聞きました。これらのタイプの問題(データ構造とアルゴリズムの問​​題)を解決するのにスイッチが役立つと思いますか?

答えて

4

destroy_tree()は2回呼び出され、一度呼び出すと、デストラクタからmain()を実行した後に呼び出されます。

leaf =!NULLであるかどうかをチェックするので、deleteはポインタをNULLに設定しないため、とにかく動作するはずです。だから、destroy_tree()が2回目に呼び出されたときにルートがNULLでない場合

+0

おかげでそれを実行しようとしないので、それがNULLであることを確認したときに、メインリターン – Steve

+0

クール。とにかく、すべてをNULLにリセットすることをお勧めしますが、それは良いプログラミングの練習です。 – PaV

0

あなたの問題は直接関係しませんが、構造体に構造体を与えるのは良い方法です。たとえば、次のように

struct node 
{ 
    int key_value; 
    node *left; 
    node *right; 

    node(int val) : key_val(val), left(NULL), right(NULL) {} 
}; 

あなたがこれを行う場合は、ノードを作成するときに、ポインタの設定について心配する必要はありません、それらを初期化することを忘れすることはできませんので、あなたのコードは、簡単になります。

DDDに関しては、それは良いデバッガですが、正にデバッグの秘密は最初に正しいコードを書くことであり、そうする必要はありません。 C++は、コンストラクタの使用のように、この方向で多くの助けを提供しますが、それが提供する機能を理解して使用する必要があります。

+0

ヒントをありがとう。構造体コンストラクタに関して、私はそれを実装しようとしていますが、コンパイルエラーが発生しています。私はそれを調べるだろうと思う。 – Steve

0

Btree :: destroy_treeは、ツリーを正常にヌークすると、 'root'に0を設定しません。その結果、デストラクタクラスdestroy_tree()はすでに破壊されているオブジェクトを破棄しようとしています。

これは未定義の動作です:)。

0

一度ルートを破棄します。
が、私は地元のデストラクタが呼び出されていることを忘れてしまった、それは(デストラクタから)再び

void Btree::destroy_tree(node *leaf) 
{ 
    if(leaf!=NULL) 
    { 
    destroy_tree(leaf->left); 
    destroy_tree(leaf->right); 
    delete leaf; 

    leaf = NULL; // add this line 
    } 
} 
+0

"leafを削除する"の前に "leaf = NULL"を設定することを意味しますか?さもなければ、それはNULLのための未定義ポインタを設定するように試みるでしょう – Steve

+0

No.削除の後。削除操作の後、ポインタリーフは無効なメモリを指しています。したがって、あなたは何かにusfullに葉を設定する必要があります。 –

関連する問題