Отбрасывание значения из указателя

Я не делал арифметики указателей в течение длительного времени, поэтому я решил, что попробую свою руку на 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, который отключает его от узла в дереве и не влияет на указатель исходного узла. Как я могу сказать, что я хочу указать tree->root->left->right на NULL вместо kill ? Нужен ли мне указатель на указатель в этом случае?

Да, если вы хотите удалить этот узел, вам нужно установить tree->root->left->right в 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; } 

Проверка нулевого указателя намеренно выполняется прямо в начале – это мешает вам обернуть рекурсивные вызовы с помощью проверки нулевого указателя.