C 使指针中的值为空

C 使指针中的值为空,c,pointers,C,Pointers,我已经很长时间没有做指针算法了,所以我想我应该试试C语言,做一个简单的二叉搜索树。然而,我无法掌握删除的诀窍。按照这些思路进行的工作正如我所期望的: typedef struct Node{ int value; struct Node *left; struct Node *right; }Node; typedef struct Tree{ struct Node* root; }Tree; int main(){ Tree *tree = cre

我已经很长时间没有做指针算法了,所以我想我应该试试C语言,做一个简单的二叉搜索树。然而,我无法掌握删除的诀窍。按照这些思路进行的工作正如我所期望的:

typedef struct Node{
    int value;
    struct Node *left;
    struct Node *right;
}Node;

typedef struct Tree{
    struct Node* root;
}Tree;

int main(){
    Tree *tree = createTree(); 

    treeInsert(10, tree);    // Inserts 10 at root
    treeInsert(30, tree);    // Inserts 30 to root->right
    treeInsert(5, tree);     // Inserts 5 to root->left
    treeInsert(7, tree);     // Inserts 7 to root->left->right
    treeInsert(12, tree);    // Inserts 12 to root->right->left

    // Removes Node "7" from the tree successfully
    free(tree->root->left->right);   // Free memory for this node in the tree
    tree->root->left->right = NULL;  // Set the pointer to NULL

    return 0;
}
我想编写一个
nodeDelete(Node*killNode)
函数来释放与节点关联的内存,然后将其指向NULL,但我发现它的工作方式与我期望的不一样

int main(){
   // ... snip ...

   Node *kill = tree->root->left->right  // Points kill node to Node "7"
   free(kill);                           // Deallocates memory
   kill = NULL;                          // Points kill to NULL, but keeps 
                                         //   tree->root->left->right **undefined** 
   // ... snip ...
}

我想我的问题是我告诉它,
kill
现在指向NULL,这将断开它与树中节点的连接,并且不会影响原始节点指针。我如何告诉它我想将
树->根->左->右-/code>指向NULL而不是
杀死
?在这种情况下,我需要一个指向指针的指针吗?

是的,如果要删除该节点,需要将
树->根->左->右
设置为
。这意味着您不能只将该指针的值传递给删除函数

您有两个选项:可以传递指向要删除的节点的父节点的指针,以及有关要删除的子节点的信息:

nodeDelete(Node *parent, int kill_right)
{
    Node *kill;

    if (kill_right) {
        kill = parent->right;
        parent->right = NULL;
    } else {
        kill = parent->left;
        parent->left = NULL;
    }

    free(kill);
}
在这种情况下,您可以调用
nodeDelete(tree->root->left,1)

或者,您可以将指针传递给要删除的指针:

nodeDelete(Node **killptr)
{
    free(*killptr);
    *killptr = NULL;
}

在这种情况下,您可以调用
nodeDelete(&tree->root->left->right)

是的,您需要使用双指针。您还需要确保递归删除要删除的节点的所有子节点:

void nodeDelete(Node **killNode)
{
    if(!*killNode)
        return;

    // Free child nodes
    nodeDelete((*killNode)->left);
    nodeDelete((*killNode)->right);

    // Free the node itself
    free(*killNode);
    *killNode=NULL;
}

空指针检查是故意在一开始就执行的——这可以防止您必须在空指针检查中包装递归调用。

只键入“struct”而不键入typedef structs确实是一种糟糕的样式。@VladLazarenko是吗?我在互联网上看到过这种建议,并认为这是一种相当普遍的做法。就像我说的,我是C的新手。我在大学里有一些C++经验,但是我会记住它。它在Linux编码风格中是很好的描述(一般适用于C,而不仅仅是Linux内核风格)。请参阅第5章-@VladLazarenko“typedef struct”并不是普遍认为有害的——请参阅此处的讨论:@VladLazarenko这只是Linux内核的样式指南。。。换句话说,完全主观。完美!双指针方法正是我想要的。我不知道,是在C中,它是否和C++中的引用变量一样工作?你可能想和第二个版本一起去——它的方式更短,并且可以删除根节点,而第一个版本不能。此外,您可能希望递归地删除子节点,以避免内存泄漏。@MartinB这就是计划(递归删除)@caf直接将
&tree->root->left->right
传递给该示例非常有效,但是如果我执行类似
节点*kill=tree->root->left->right这样的操作,它将失败(内存空间未被清空)
nodeDelete(&kill)
..@KChaloux:一元
&
运算符是C-它返回左值的地址(如:给定可寻址对象
a
&x
是指向
a
的指针)。但是,C++中的<>代码>和<代码>可用于声明器,而不是C++,因此不存在C++风格的引用变量。请注意,
*killptr
必须用于显式取消引用
nodeDelete()
@KChaloux:Yes-节点删除基本上是一种改变节点父节点的操作,因此最终必须向
nodeDelete()
提供对父节点的引用。使用
&tree->root->left->right
有效,因为它是对父节点中
.right
成员的引用;使用
&kill
不会,因为它根本不是对父节点任何部分的引用。