Search code examples
cpointerstreestructure

Tree node with arbitrary many child nodes in C


I'm trying to implement a node structure in C that can have arbitrary many child nodes. I wanted to do this idea by using a pointer to a pointer to a struct instead of using an array:

struct Node {
    char name[10];  // Name of the node.
    int data;       // The data it holds.
    struct Node *parent; // The parent node.
    struct Node **child; //
};

(I don't know if this is the best or even a good but I'm just playing around to learn C better). I also implemented a print function that prints the members:

void print(struct Node node);

(I know this only prints one node so it wouldn't work for a node with multiple child-nodes). However, when I try to use this in a main function I get a segmentation fault (core dump):

#include <stdio.h>
#include <stdlib.h>

struct Node {
    char name[10];  // Name of the node.
    int data;       // The data it holds.
    struct Node *parent; // The parent node.
    struct Node **child; //
};

void print(struct Node node) {
    printf("Name: %s\n", node.name);
    printf("Data: %d\n", node.data);
    printf("Parent: %s\n", (*node.parent).name);
    printf("Children: %s\n", (**node.child).name);
}

int main() {
    struct Node n1 = { "Parent", 1, NULL, NULL };
    struct  Node n2 = { "Child1", 2, &n1, NULL };
   
    *n1.child = &n2;
   
    print(n1);
    print(n2);
   
    return 0;
}

Can anybody see what I'm doing wrong here and what I should do instead?

Kind regards,

Edit:

Actually what I wanted to achieve was to create the child member like this (I'm using an example with an array of integers to illustrate what I mean):

int *p = malloc(sizeof(int));
*p =1;
*(p+1)=2;

but instead of p pointing to integers having it point to pointers to struct Node. Is this doable?


Solution

  • You get a segmentation fault because you do not test if the parent node is valid, nor if the child node is a valid pointer, nor that the pointer it points to is valid too. The initialization of n1.child[0] is incorrect too.

    • *n1.child = &n2; has undefined behavior because n1.child is a null pointer.
    • printf("Parent: %s\n", (*node.parent).name); has undefined behavior for n1;
    • printf("Children: %s\n", (**node.child).name); has undefined behavior for n2.

    Alos note that it is idiomatic in C to pass structure pointers rather than copies of structures to functions such as print.

    Here is a modified version, assuming child, if not NULL points to a NULL terminated array of node pointers.

    EDIT: I added an add_child function to illustrate how to construct trees from individual nodes.

    #include <stdio.h>
    #include <stdlib.h>
    
    struct Node {
        char name[10];  // Name of the node.
        int data;       // The data it holds.
        struct Node *parent; // The parent node.
        struct Node **child; // if not NULL, points to a NULL terminated array of pointers.
    };
    
    void print(const struct Node *node) {
        if (node) {
            printf("Name: %s\n", node->name);
            printf("Data: %d\n", node->data);
            if (node->parent) {
                printf("Parent: %s\n", node->parent->name);
            }
            if (node->child) {
                printf("Children:");
                for (int i = 0; node->child[i]; i++) {
                    printf("%s %s", i > 0 ? "," : "", node->child[i]->name);
                }
                printf("\n");
            }
        }
    }
    
    // add a child node to a parent's child list.
    // return 0 upon success or an error code on failure
    int add_child(struct Node *parent, struct Node *chid) {
        if (parent == NULL)
            return 1;
        if (child == NULL)
            return 2;
        size_t nchild = 0;
        if (parent->child != NULL) {
            while (parent->child[nchild] != NULL)
                nchild++;
        }
        struct Node *new_child = realloc(parent->child, (nchild + 2) * sizeof(*new_child));
        if (new_child == NULL)
            return 3;
        parent->child = new_child;
        parent->child[nchild++] = child;
        parent->child[nchild] = NULL;
        child->parent = parent;
        return 0;
    }
    
    int main() {
        struct Node n1 = { "Parent", 1, NULL, NULL };
        struct Node n2 = { "Child1", 2, NULL, NULL };
        struct Node n3 = { "Child2", 3, NULL, NULL };
    
        add_child(&n1, &n2);
        add_child(&n1, &n3);
       
        print(&n1);
        print(&n2);
        print(&n3);
       
        return 0;
    }