2017-02-20 5 views
1

Löschen Ich habe eine Funktion implementiert, die den Baumknoten zusammen mit seinen Unterstrukturen wie diese löscht:C Endlosschleife nach Binärbaum

void DeleteTree(BTreeNode * bt){ 
    if(bt == NULL) 
     return; 

    DeleteTree(bt->left); 
    DeleteTree(bt->right); 

    printf("del tree data: %d \n", bt->data); 
    free(bt); 
} 

Und dann habe ich eine andere Funktion, die den Baum durchquert:

void PreorderTraverse(BTreeNode * bt, VisitFuncPtr action){ 
    if(bt == NULL) 
     return; 

    action(bt->data); 
    PreorderTraverse(bt->left, action); 
    PreorderTraverse(bt->right, action); 
} 

Hier ist der Parameter "action" ein Funktionszeiger, der die Daten des Knotens als Argument verwendet und void return type hat, um eine andere Funktion aufzurufen, die die Daten des Knotens ausgibt.

Hier ist meine Haupt:

#include <stdio.h> 
#include <stdlib.h> 
#include "BinaryTree.h" 

void ShowIntData(int data){ 
    printf("%d ", data); 
} 

int main(){ 
    BTreeNode * bt1 = MakeBTreeNode(); 
    BTreeNode * bt2 = MakeBTreeNode(); 
    BTreeNode * bt3 = MakeBTreeNode(); 
    BTreeNode * bt4 = MakeBTreeNode(); 
    BTreeNode * bt5 = MakeBTreeNode(); 
    BTreeNode * bt6 = MakeBTreeNode(); 

    SetData(bt1, 1); 
    SetData(bt2, 2); 
    SetData(bt3, 3); 
    SetData(bt4, 4); 
    SetData(bt5, 5); 
    SetData(bt6, 6); 

    MakeLeftSubTree(bt1, bt2); 
    MakeRightSubTree(bt1, bt3); 
    MakeLeftSubTree(bt2, bt4); 
    MakeRightSubTree(bt2, bt5); 
    MakeRightSubTree(bt3, bt6); 

    PreorderTraverse(bt1, ShowIntData); 
    printf("\n"); 
    DeleteTree(bt3); 
    PreorderTraverse(bt1, ShowIntData); 

    return 0; 
} 

Das Problem ist, nach DeleteTree, wenn PreorderTraverse erneut aufgerufen wird, wird das Programm in eine Endlosschleife fällt, einige Werte Müll ausdrucken. Kannst du mir bitte erklären, warum es passiert? Zu Ihrer Information, ich zeige Ihnen BinaryTree.h und BinaryTree.c unten für Ihre Referenz.

BinaryTree.h

#ifndef __BINARY_TREE_H__ 
#define __BINARY_TREE_H__ 

typedef int BTData; 

typedef struct _bTreeNode{ 
    BTData data; 
    struct _bTreeNode * left; 
    struct _bTreeNode * right; 
} BTreeNode; 

BTreeNode * MakeBTreeNode(void); 
BTData GetData(BTreeNode * bt); 
void SetData(BTreeNode * bt, BTData data); 

BTreeNode * GetLeftSubTree(BTreeNode * bt); 
BTreeNode * GetRightSubTree(BTreeNode * bt); 

void MakeLeftSubTree(BTreeNode * main, BTreeNode * sub); 
void MakeRightSubTree(BTreeNode * main, BTreeNode * sub); 

typedef void VisitFuncPtr(BTData data); 

void PreorderTraverse(BTreeNode * bt, VisitFuncPtr action); 
void InorderTraverse(BTreeNode * bt, VisitFuncPtr action); 
void PostorderTraverse(BTreeNode * bt, VisitFuncPtr action); 

void DeleteTree(BTreeNode * bt); 

#endif // __BINARY_TREE_H__ 

BinaryTree.c

#include <stdio.h> 
#include <stdlib.h> 
#include "BinaryTree.h" 

BTreeNode * MakeBTreeNode(void){ 
    BTreeNode * nd = (BTreeNode*)malloc(sizeof(BTreeNode)); 

    nd->left = NULL; 
    nd->right = NULL; 
    return nd; 
} 

BTData GetData(BTreeNode * bt){ 
    return bt->data; 
} 

void SetData(BTreeNode * bt, BTData data){ 
    bt->data = data; 
} 

BTreeNode * GetLeftSubTree(BTreeNode * bt){ 
    return bt->left; 
} 

BTreeNode * GetRightSubTree(BTreeNode * bt){ 
    return bt->right; 
} 

void MakeLeftSubTree(BTreeNode * main, BTreeNode * sub){ 
    if(main->left != NULL) 
     free(main->left); 

    main->left = sub; 
} 

void MakeRightSubTree(BTreeNode * main, BTreeNode * sub){ 
    if(main->right != NULL) 
     (main->right); 

    main->right = sub; 
} 

void PreorderTraverse(BTreeNode * bt, VisitFuncPtr action){ 
    if(bt == NULL) 
     return; 

    action(bt->data); 
    PreorderTraverse(bt->left, action); 
    PreorderTraverse(bt->right, action); 
} 

void DeleteTree(BTreeNode * bt){ 
    if(bt == NULL) 
     return; 

    DeleteTree(bt->left); 
    DeleteTree(bt->right); 

    printf("del tree data: %d \n", bt->data); 
    free(bt); 
} 

Thank you very much.

+0

Zeit zu lernen, wie ein Debugger verwenden .... – LPs

+0

Ich benutze den Debugger und es sagt der Fehler passiert bei der Funktion ShowIntData, aber wenn der Speicher für den Baum Knoten freigegeben ist, sollte der Parameter bt in PreorderTraverse gleich NULL sein und f entkommen Salbung? – Ned

+0

Siehe meine Antwort. free setzt den übergebenen Zeiger nicht automatisch auf 'NULL'. Sie sollten es mit Ihrem Debugger sehen. – LPs

Antwort

3

free setzt den übergebenen Zeiger nicht auf NULL.

Aufruf PreorderTraverse nach dem Löschen rufen Sie Undefined Behavior auf, da die Funktion versucht, den freigegebenen dynamischen Speicher zu dereferenzieren.

+0

Das war der Grund ... Vielen Dank! Wenn ich dann den übergebenen Zeiger auf NULL setzen möchte, muss ich das nach free(); – Ned

+0

Ja, Sie müssen es manuell tun. – LPs

+2

@Ned Es wird wesentlich komplizierter. Der Zeiger, den Sie auf Null setzen müssen, ist der Kindzeiger im Knoten * parent * (der rechte Knotenzeiger des 'bt1'). Der Zeiger 'bt3' hat nichts mit Ihrem aktuellen Baum zu tun, außer dass er ursprünglich auf einen Knoten zeigt, den Sie eingefügt haben. Ehrlich gesagt, dass du es immer noch herumschleppst, ist eine schlechte Idee. In der Baumstruktur sollte der Zugriff über den referenzierenden Zeiger * des Baums erfolgen. Ich rate Ihnen dringend, sich mit der Verwendung von Zeigern auf Zeiger vertraut zu machen. Es ist nahezu unmöglich, den richtigen Baumverwaltungscode in C zu schreiben, ohne dies zu tun. – WhozCraig

0

Zeilennummer 38 auf BinaryTree.c (Funktion MakeRightSubTree) sollten

free(main->right);

statt

(main->right);

+0

Entschuldigung, ich könnte es versauen, während ich kopiert und eingefügt wurde ... – Ned