1

I am having some trouble with pointers in C. Basically, we are tasked with programming an N-ary tree (family tree). Any single node can have any number of children (0, 1, 2, ...). I am stuck at the part of adding a single parent and a single child.

Theoretically, the parent should be the root and the child should be the child of the root. My add_child method is as follows (so far):

Node* add_child(Node** root, char* parent, char* child) {
    Node* new_node = malloc(sizeof(Node));
    //check for correct memory allocation of new_node here
    new_node->name = child;
    new_node->children = NULL;
    new_node->child_count = 0;

    if (*root == NULL) {
        Node* parent = malloc(sizeof(Node));
        parent->name = parent;
        parent->children = malloc(sizeof(NodeList*));
        NodeList* list = malloc(sizeof(NodeList));
        list->data = new_node;
        list->next = NULL;
        parent->children = &list;
        parent->child_count = 1;
        *root = parent;
        return;
    }
}

Here are the structs:

typedef struct FieldNode {
    char* name;
    NodeList** children;
    size_t child_count;
} Node;

typedef struct FieldNode_L {
    Node* data;
    NodeList* next;
} NodeList;

Now that we have that out of the way, I'll move onto the print_tree function, we should print the tree breadth-first (level-by-level). I have written the algorithm for this already, but it gets stuck pushing the children of a node onto the queue. To do this:

NodeList* current = *listPtr;
while (current->data != NULL) {
    Node* to_add = current->data;
    // set up queuenode and push it to the queue
    current = current->next;
}

So theoretically, it should run once, push to the queue, then set current to the next, which is null, go back to check the while-loop condition, and fail and continue through the rest of the print_tree method. But this doesn't happen.

After debugging with gdb for what seems like 5 hours, I can tell you this:

  • Before returning in add_child method, all of the memory locations are valid and point to the correct places. In gdb, with a breakpoint set, I can display all of the information through the root pointer (parent name, child count, and child name) by dereferencing.
  • In the print_tree method, all of the information retains from the root that was set in the add_child method EXCEPT the children.
  • The address that was set in the add_child method, and which I confirmed held the name I inputted had changed to a string filled with unicode characters ("\237\432\320....etc etc")
  • My algorithm correctly prints the parent name, but then fails when adding the children and goes into an infinite loop as described above in the last code block.

So all in all, I have no idea why the contents have changed. I suspect that I am assigning values/addresses wrong in add_child (because the information is retained within the add_child function, but is lost in the other method) but I am confused because the root is holding some information but not all of it across functions.

I am very new at C and still trying to learn all this pointer stuff, for example double pointers... Any help with this problem would be appreciated!

VALGRIND EDIT: As requested, here is the valgrind output of the program, although I don't see how it is helpful. My code runs into an infinite loop, so my program has no chance to clean up the mess. In the last code block, where I show where how/where it infinite-loops, I commented out code that allocated space for a QueueNode. After running forever, it racks up a bunch of allocates but only 2 frees. That's why the output says it has that many.

GCC EDIT: As requested, I ran gcc with the flags -Wall -Wextra -pedantic and received the following output:

10:26: warning: unused parameter 'argv' [-Wunused-parameter]
154:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
89:1: warning: control reaches end of non-void function [-Wreturn-type]

I fixed the last two (comparison between signed and unsigned and the control reaching the end of a non-void function). The unused parameter I need later on, so I can't change that yet. It shouldn't effect anything anyway.

After fixing those problems, nothing has changed - the same error still occurs.

Some Guy
  • 351
  • 1
  • 4
  • 20
  • I would appreciate you showing the struct. – Tatsuyuki Ishi Mar 13 '17 at 02:45
  • I would also recommend valgrind for mysterious memory errors. – Tatsuyuki Ishi Mar 13 '17 at 02:45
  • @TatsuyukiIshi I added in the struct definitions, I'll work on the valgrind output. – Some Guy Mar 13 '17 at 02:50
  • 1
    It seems you're performing operation on uninitialized Node. Please check line 72 mentioned by valgrind. – Tatsuyuki Ishi Mar 13 '17 at 03:05
  • @TatsuyukiIshi It is initialized. Line 72 is in the add_child function. After I perform all of those operations but before I returned, I set a breakpoint inside the function. Displaying all of the values of all of the variables/addresses confirmed that I had indeed set them correctly, but they were lost when I exited the function. I explained this in my OP. Everything else stuck (name of parent and child size), but the actual children did not. – Some Guy Mar 13 '17 at 03:08
  • Compile with warnings enabled! `warning: assignment from incompatible pointer type [-Wincompatible-pointer-types] parent->name = parent;` and `warning: ‘return’ with no value, in function returning non-void return;` – Antti Haapala -- Слава Україні Mar 13 '17 at 05:28
  • @AnttiHaapala I added a GCC warnings section in OP. Same error still occurs after fixing everything in there:/ – Some Guy Mar 13 '17 at 12:37
  • `parent->children = &list;` here you're storing the pointer to the *local variable `list`, which dies when the function returns. – Antti Haapala -- Слава Україні Mar 13 '17 at 15:26
  • @AnttiHaapala I suspected something as such... how would i go about changing it so it doesnt die? I thought since i allocated space for it on the heap and didnt free it, it would persist through the function? – Some Guy Mar 13 '17 at 15:30
  • @DevinK idk if you even should have a double pointer there, just `NodeList *children` – Antti Haapala -- Слава Україні Mar 13 '17 at 16:22
  • @AnttiHaapala I'll try changing it when I get off of work... would changing it fix it or would the same problem persist? – Some Guy Mar 13 '17 at 16:31

0 Answers0