Search code examples
crecursionbinary-treefreefunction-definition

what does !temp->left mean in C?


I am studying binary search trees right now, and I came across this code

void free_tree(Node* root) {
    // Deallocates memory corresponding
    // to every node in the tree.
    Node* temp = root;
    if (!temp)
        return;
    free_tree(temp->left);
    free_tree(temp->right);
    if (!temp->left && !temp->right) {
        free(temp);
        return;
    }
}

what does !temp mean in this context? Does it mean if temp == NULL? and does that mean !temp->left or !temp->right mean "if right of temp == NULL"? I'm kind of confused with this code in general.

I tried searching for related questions, but so far got no answers.


Solution

  • From the C Standard (6.5.3.3 Unary arithmetic operators)

    5 The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).

    and (6.3.2.3 Pointers)

    3 An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

    So these if statements

    if (!temp)
    

    and

    if (!temp->left && !temp->right) {
    

    is equivalent to

    if ( temp == NULL )
    

    and

    if ( temp->left == NULL && temp->right == NULL ) {
    

    Pay attention to that your function is wrong. It frees only memory for nodes data members left and right of which are null pointers.

    A correct function can look for example the following wat

    void free_tree( Node *root ) 
    {
        // Deallocates memory corresponding
        // to every node in the tree.
        if ( root != NULL )
        {
            free_tree( root->left );
            free_tree( root->right );
    
            free( root );
        }
    }
    

    Though it will be better to declare and define it the following way

    void free_tree( Node **root ) 
    {
        // Deallocates memory corresponding
        // to every node in the tree.
        if ( *root != NULL )
        {
            free_tree( &( *root )->left );
            free_tree( &( *root )->right );
    
            free( *root );
            *root = NULL;
        }
    }
    

    After calling the function the original pointer to the root node passed to the function by reference through pointer to it will be equal to NULL.