Search code examples
cstructpointer-to-pointer

a nested struct with pointers


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct node *tree_ptr;
typedef struct table * Table;
struct node
{
    char* element;
    tree_ptr left, right;
};

typedef struct table
{
    tree_ptr head;
    int tree_h;
}table;
char* key = NULL;
Table insert(char* insert_key,Table t)
{
    int height = 0;
    //tree_ptr ptr = t->head;
    tree_ptr *ptr = &(t->head);
    key = strdup(insert_key);

    tree_ptr new_node = malloc(sizeof(struct node));
    new_node->element = key;
    new_node->left = NULL;
    new_node->right = NULL;

    if ( t->head==NULL ){
        *ptr = new_node;
        t->tree_h = 0;
        printf("head:%s\n",t->head->element);
        return t;
    }

    while(1){
        if ( strcmp(insert_key, (*ptr)->element)<0 ){
            if ( (*ptr)->left ==NULL ){
                (*ptr)->left = new_node;
                height++;
                if ( height > t->tree_h)
                    t->tree_h = height;
                break;
            }
            else{
                (*ptr) = (*ptr)->left;
                height++;
            }
        }
        else if ( strcmp(insert_key, (*ptr)->element)>0 ){
            if ( (*ptr)->right ==NULL ){
                (*ptr)->right = new_node;
                height++;
                if ( height > t->tree_h)
                    t->tree_h = height;
                break;
            }
            else{
                (*ptr) = (*ptr)->right;
                height++;
            }
        }
        else break;
    }

    return t;

}

int main() {
    Table t = malloc(sizeof(table));
    t->head = NULL;

    t = insert("one", t);
    t = insert("two", t);
    t = insert("three", t);

    printf("%s\n",t->head->element);
   return 0;
}

The above is a simplified program, some definition code is given, so I could not change the basic structure, like table, Table, node, tree_ptr, while others could be changed. What I am trying to implement is a spellchecking, the table stored the head of the tree and some other properties of the tree(which is omitted here), the tree is implemented as an ordered binary tree.

I find that, insert() works well up to two times, after the (*ptr) = (*ptr)->right; the t->head is changed as well. So after using it two times, I lost the head of the tree.

How to modify my insert()?


Solution

  • To insert a node into a tree you first have to search for an empty leaf. Apart from this you do not modify t, so there is no need of writing it back by return value:

    void insert( char* insert_key, Table t )
    {
        // serach empty leaf, where to insert the new node
        tree_ptr *ptr = &(t->head);     // start at head
        while ( *ptr != NULL )          // end if empty leaf is found
        {
            int cmpRes = strcmp( insert_key, (*ptr)->element );
            if ( cmpRes == 0 )
                return;                 // insert_key already is member of tree 
            if ( cmpRes < 0 )
                ptr = &((*ptr)->left);  // step down to left child
            else
                ptr = &((*ptr)->right); // step down to right child
        }
    
        // create new node
        tree_ptr new_node = malloc( sizeof(struct node) );
        new_node->element = strdup( insert_key );
        new_node->left = NULL;
        new_node->right = NULL;
    
        // place new node at empty leaf
        *ptr = new_node;
    }
    

    With this recursive function you can print your tree:

    void printTree( tree_ptr ptr )
    {
        if ( ptr == NULL )
            return;
        printTree( ptr->left );
        printf( "%s\n", ptr->element );
        printTree( ptr->right );
    }
    
    printTree( t->head );
    

    And with this one you can free all nodes of your tree:

    void deleteTree( tree_ptr ptr )
    {
        if ( ptr == NULL )
            return;
        deleteTree( ptr->left );
        deleteTree( ptr->right );
        free( ptr );
    }
    
    deleteTree( t->head );
    t->head = NULL;