2009-06-14 17 views
2

Ich schrieb ein Programm, um meinen Binärbaum zu testen und wenn ich es ausführe, scheint das Programm abzustürzen (btree.exe funktioniert nicht mehr, Windows sucht nach einer Lösung ...).segfault nach Rückgabe 0;

Als ich es durch meinen Debugger lief und den Haltepunkt auf die Funktion platzierte, die ich vermute, verursacht es, destroy_tree(), schien es wie erwartet zu laufen und kehrte zur Hauptfunktion zurück. Main, wiederum, kehrte aus dem Programm, aber dann sprang der Cursor zurück zu destroy_tree() und rekursiv in sich geschleift.

Das minimale Codebeispiel ist unten, so dass es sofort ran werden kann. Mein Compiler ist MinGW und mein Debugger ist Gdb (ich verwende 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; 
} 

Als beiseite, ich bin der Planung für das Debuggen, diese Probleme von Code :: Blocks integrierten Debugger auf DDD wechseln. Ich habe gehört, DDD kann visuelle Zeiger auf Objekte anzeigen, anstatt nur die Adresse des Zeigers anzuzeigen. Denken Sie, dass die Umstellung die Lösung dieser Art von Problemen (Probleme mit Datenstrukturen und Algorithmen) erleichtert?

Antwort

4

Ihre destroy_tree() zweimal aufgerufen werden, rufen Sie sie einmal und dann wird es aufgerufen, nachdem die Ausführung Hauptblätter() aus dem destructor.

Sie mögen denken, es trotzdem funktionieren sollte, weil Sie, ob Blatt überprüfen! = NULL, aber nicht gelöscht den Zeiger auf NULL gesetzt. So ist Ihr root nicht NULL, wenn destroy_tree() zum zweiten Mal aufgerufen wird,

+0

Danke, ich habe vergessen, dass die lokalen Destruktoren aufgerufen werden, wenn der Haupt kehrt – Steve

+0

kühlen. Obwohl ich vorschlagen möchte, dass Sie alles auf NULL zurücksetzen, ist es eine gute Programmierpraxis. – PaV

0

Nicht direkt verwandt (oder vielleicht ist es) zu Ihrem Problem, aber es ist gute Praxis, Strukturen einen Konstruktor zu geben. Zum Beispiel:

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

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

Wenn Sie das tun, Ihr Code wird einfacher, weil Sie kümmern sich nicht um die Zeiger eingestellt wird, wenn Sie einen Knoten zu erstellen, und es ist nicht möglich, zu vergessen, sie zu initialisieren.

In Bezug auf DDD, es ist ein feiner Debugger, aber ehrlich gesagt ist das Geheimnis des Debuggens, erstens richtigen Code zu schreiben, so dass Sie es nicht tun müssen. C++ gibt Ihnen eine Menge Hilfe in dieser Richtung (wie die Verwendung von Konstruktoren), aber Sie müssen die Möglichkeiten, die es bietet, verstehen und verwenden.

+0

Danke für die Tipps. Im Hinblick auf den struct-Konstruktor versuche ich, es zu implementieren, aber Kompilierungsfehler zu bekommen. Ich denke, ich werde mich darum kümmern. – Steve

0

Btree :: destroy_tree nicht gesetzt 'root' auf 0, nachdem der Baum erfolgreich nuking. Als Ergebnis wird die Destruktor-Klasse destroy_tree() erneut und Sie versuchen, bereits zerstörte Objekte zu zerstören.

Das wird dann Verhalten undefiniert sein :).

0

Sobald Sie die Wurzel zerstören.
Stellen Sie sicher, es NULL ist, so dass es es nicht versuchen Sie es erneut zu tun (von der destructor)

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

Sie meinen "Blatt = NULL" vor "Blatt löschen" richtig? Andernfalls würde es versuchen, einen undefinierten Zeiger auf Null – Steve

+0

Nr. Nach dem Löschen festzulegen. Nach der Löschoperation zeigt das Zeigerblatt auf ungültigen Speicher. Also müssen Sie sich auf etwas Nützliches einstellen. –