C standard binary trees

binary-tree, c, data-structures, tree

Solution

Several problems:

You haven't shown us the definition of type `nodeBT`, but you've declared `aux`, `root`, and `parent` to be pointers to that type.

You then assign `aux` to point to a `BinaryTree` even though it's declared to point to a `nodeBT`.

You assign to `aux->dr`, which isn't part of `BinaryTree`, so I can't just assume you typed `nodeBT` where you meant `BinaryTree`. You assign to `nodeBT->st`, that is not a part of `BinaryTree` either.

You try to return the parsed tree by assigning `nodeBT=root`. The problem is that C is a “call-by-value” language. This implies that when your `create` function assigns to `nodeBT`, it is only changing its local variable's value. The caller of `create` doesn't see that change. So the caller doesn't receive the root node. That's probably why you're getting your “memory unreadable” error; the caller is accessing some random memory, not the memory containing the root node.

Your code will actually be much easier to understand if you write your parser using a standard technique called “recursive descent”. Here's how.

Let's write a function that parses one node from the expression string. Naively, it should have a signature like this:

BinaryTree *nodeFromExpression(char const *expression) {

To parse a node, we first need to get the node's `info`:

    char info = expression[0];

Next, we need to see if the node should have children.

    BinaryTree *leftChild = NULL;
    BinaryTree *rightChild = NULL;
    if (expression[1] == '(') {

If it should have children, we need to parse them. This is where we put the “recursive” in “recursive descent”: we just call `nodeFromExpression` again to parse each child. To parse the left child, we need to skip the first two characters in `expression`, since those were the info and the `(` of the current node:

        leftChild = nodeFromExpression(expression + 2);

But how much do we skip to parse the right child? We need to skip all the characters that we used while parsing the left child…

        rightChild = nodeFromExpression(expression + ??? 

We don't know how many characters that was! It turns out we need to make `nodeFromExpression` return not just the node it parsed, but also some indication of how many characters it consumed. So we need to change the signature of `nodeFromExpression` to allow that. And what if we run into an error while parsing? Let's define a structure that `nodeFromExpression` can use to return the node it parsed, the number of characters it consumed, and the error it encountered (if there was one):

typedef struct {
    BinaryTree *node;
    char const *error;
    int offset;
} ParseResult;

We'll say that if `error` is non-null, then `node` is null and `offset` is the offset in the string where we found the error. Otherwise, `offset` is just past the last character consumed to parse `node`.

So, starting over, we'll make `nodeFromExpression` return a `ParseResult`. It will take the entire expression string as input, and it will take the offset in that string at which to start parsing:

ParseResult nodeFromExpression(char const *expression, int offset) {

Now that we have a way to report errors, let's do some error checking:

    if (!expression[offset]) {
        return (ParseResult){
            .error = "end of string where info expected",
            .offset = offset
        };
    }
    char info = expression[offset++];

I didn't mention this the first time through, but we should handle your `$` token for NULL here:

    if (info == '$') {
        return (ParseResult){  
            .node = NULL,
            .offset = offset   
        };
    }

Now we can get back to parsing the children.

    BinaryTree *leftChild = NULL;
    BinaryTree *rightChild = NULL;
    if (expression[offset] == '(') {

So, to parse the left child, we just call ourselves recursively again. If the recursive call gets an error, we return the same result:

        ParseResult leftResult = nodeFromExpression(expression, offset);
        if (leftResult->error)
            return leftResult;

OK, we parsed the left child successfully. Now we need to check for, and consume, the comma between the children:

        offset = leftResult.offset;
        if (expression[offset] != ',') {
            return (ParseResult){
                .error = "comma expected",
                .offset = offset
            };
        }
        ++offset;

Now we can recursively call `nodeFromExpression` to parse the right child:

        ParseResult rightResult = nodeFromExpression(expression, offset);

The error case now is a bit more complex if we don't want to leak memory. We need to free the left child before returning the error:

        if (rightResult.error) {
            free(leftResult.node);
            return rightResult;
        }

Note that `free` does nothing if you pass it `NULL`, so we don't need to check for that explicitly.

Now we need to check for, and consume, the `)` after the children:

        offset = rightResult.offset;
        if (expression[offset] != ')') {
            free(leftResult.node);
            free(rightResult.node);
            return (ParseResult){
                .error = "right parenthesis expected",
                .offset = offset
            };
        }
        ++offset;

We need to set our local `leftChild` and `rightChild` variables while the `leftResult` and `rightResult` variables are still in scope:

        leftChild = leftResult.node;
        rightChild = rightResult.node;
    }

We've parsed both children, if we needed to, so now we're ready to construct the node we need to return:

    BinaryTree *node = (BinaryTree *)calloc(1, sizeof *node);
    node->info = info;
    node->left = leftChild;
    node->right = rightChild;

We have one last thing to do: we need to set the `father` pointers of the children:

    if (leftChild) {
        leftChild->father = node;
    }
    if (rightChild) {
        rightChild->father = node;
    }

Finally, we can return a successful `ParseResult`:

    return (ParseResult){
        .node = node,
        .offset = offset
    };
}

I've put all the code in this gist for easy copy'n'paste.

UPDATE

If your compiler doesn't like the `(ParseResult){ ... }` syntax, you should look for a better compiler. That syntax has been standard since 1999 (§6.5.2.5 Compound Literals). While you're looking for a better compiler, you can work around it like this.

First, add two static functions:

static ParseResult ParseResultMakeWithNode(BinaryTree *node, int offset) {
    ParseResult result;
    memset(&result, 0, sizeof result);
    result.node = node;
    result.offset = offset;
    return result;
}

static ParseResult ParseResultMakeWithError(char const *error, int offset) {
    ParseResult result;
    memset(&result, 0, sizeof result);
    result.error = error;
    result.offset = offset;
    return result;
}

Then, replace the problematic syntax with calls to these functions. Examples:

    if (!expression[offset]) {
        return ParseResultMakeWithError("end of string where info expected",
            offset);
    }
    if (info == '$') {
        return ParseResultMakeWithNode(NULL, offset);
    }

Problem

I'm pretty much of a noob in regards to C programming. Been trying for a few days to create a binary tree from expressions of the form: ``` A(B,C(D,$)) ``` Where each letters are nodes. `'('` goes down a level in my tree (to the right). `','` goes to the left-side branch of my tree `'$'` inserts a NULL node. `')'` means going up a level. This is what I came up with after 2-3 days of coding: ``` #define SUCCESS 0 typedef struct BinaryTree { char info; BinaryTree *left,*right,*father; }BinaryTree; int create(BinaryTree*nodeBT, const char *expression) { nodeBT *aux; nodeBT *root; nodeBT *parent; nodeBT=(BinaryTree*) malloc (sizeof(BinaryTree)); nodeBT->info=*expression; nodeBT->right=nodeBT->left=NULL; nodeBT->father = NULL; ++expression; parent=nodeBT; root=nodeBT; while (*expression) {if (isalpha (*expression)) {aux=(BinaryTree*) malloc (sizeof(BinaryTree)); aux->info=*expression; aux->dr=nodeBT->st=NULL; aux->father= parent; nodeBT=aux;} if (*expression== '(') {parent=nodeBT; nodeBT=nodeBT->dr;} if (*expression== ',') {nodeBT=nodeBT->father; nodeBT=nodeBT->dr;} if (*expression== ')') {nodeBT=nodeBT->father; parent= nodeBT->nodeBT;} if (*expression== '$') ++expression; ++expression; } nodeBT=root; return SUCCESS; } ``` At the end, while trying to access the newly created tree, I keep getting "memory unreadable 0xCCCCCC". And I haven't got the slightest hint where I'm getting it wrong. Any idea ?

Original source