Ошибки Valgrind из-за свободной памяти? - PullRequest
1 голос
/ 28 октября 2019

Я получаю эти ошибки Valgrind, но на самом деле не знаю, что я сделал не так. Я предполагаю, что я использую указатели, которые указывают на свободное место в памяти. Любая помощь?

enter image description here

Node* insertNode(Node *root, int value){

    if(!root) {
        root = malloc(sizeof(struct Node));
        root->data = value;
        root->left = root->right = NULL;
    }
    else if(value > root->data && root->right) {
        insertNode(root->right, value);
    }
    else if(value > root->data && !root->right) {
        root->right = insertNode(root->right, value);
    }
    else if(root->left) {
        insertNode(root->left, value);
    }
    else {
        root->left = insertNode(root->left, value);
    }

    return root;

}

Node* deleteNode(Node *root, int value) {

    if (root == NULL) 
        return root; 

    else if (value < root->data) {
        root->left = deleteNode(root->left, value); 
    }

    else if (value > root->data) {
        root->right = deleteNode(root->right, value); 
    }

    else if (root->left == NULL) { 
        Node *temp;
        temp = root->right; 
        free(root); 
        return temp; 
    } 

    else if (root->right == NULL) { 
        Node *temp;
        temp = root->left; 
        free(root); 
        return temp; 
        }  

    else {
        Node *temp;
        temp = smallestNode(root->right); 
        root->data = temp->data; 
        root->right = deleteNode(root->right, temp->data); 
    } 

    return root; 

}

Node* freeSubtree(Node *N) { if(!N) return;

    freeSubtree(N->left);
    free(N);
    freeSubtree(N->right);

}

1 Ответ

3 голосов
/ 29 октября 2019

Один из способов поймать некоторые из этих вещей по своему усмотрению - сделать так, чтобы точка всегда обнуляла любой указатель, который вы освободили, чтобы у него никогда не было длительной ссылки.

Node* freeSubtree(Node *N) { if(!N) return;

  freeSubtree(N->left);

  free(N); N = NULL;          // NULL out the pointer!

  freeSubtree(N->right);
}

иконечно @Johnny Mopp указал на реальную ошибку, которая требует от вас переместить free() в конец.

На практике для такого кода я становлюсь еще более агрессивным в C с любой функцией, которая может освободитьпамяти, передавая адрес указателя, так что сам адрес может быть обнулен в вызывающей стороне .

Node *freeSubtree(Node **PN)
{
  if (!PN  ||  !*PN) return;

  freeSubtree( &( (*PN)->left) );   // frees and NULLs the ->left pointer
  freeSubtree( &( (*PN)->right) );  // frees and NULLs the ->right pointer

  free(*PN);
  *PN = NULL;  // NULL the *caller's* handle on the pointer
}

Если вы хотите использовать эту технику, выдействительно нужно идти ва-банк, потому что параметр address-of-pointer обычно получает довольно широкое распространение, но это удача - никогда не иметь ошибок, связанных с использованием после освобождения.

Редактировать: ошибки с использованием после освобожденияне всегда просто ошибки, иногда они ошибки безопасности ошибки.

Примечание: в C ++ вы можете использовать параметры ref, чтобы сделать это гораздо более читабельно.

...