[Solved] Function to turn a Binary Tree into the sums of all nodes below each node; segmentation fault if I don’t create a new binary tree [closed]


It is a nuisance when we have to create an MCVE from fragments of a program. However, it’s doable — it’s a pain, but doable.

Here’s my variation on your code. Of the 115 lines shown, 35 are what you wrote in the question — roughly. So, I had to create twice as much code to create a semi-plausible MCVE.

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

typedef struct ABin_s *ABin;
struct ABin_s
{
    int valor;
    ABin esq;
    ABin dir;
};

ABin somasAcA_OK(ABin a);
int getsums(ABin a);
ABin somasAcA(ABin a);

static ABin newABin(int valor, ABin esq, ABin dir)
{
    ABin ab = malloc(sizeof(*ab));
    if (ab == 0)
    {
        fprintf(stderr, "Failed to malloc %zu bytes\n", sizeof(*ab));
        exit(EXIT_FAILURE);
    }
    ab->valor = valor;
    ab->esq = esq;
    ab->dir = dir;
    return ab;
}

int getsums(ABin a)
{
    if (a == NULL)
        return 0;
    int esq = getsums(a->esq);
    int dir = getsums(a->dir);
    return(a->valor + esq + dir);
}

ABin somasAcA_OK(ABin a)
{
    ABin b, *res;
    res = &b;

    if (a != NULL)
    {
        b = newABin(getsums(a), NULL, NULL);
        b->esq = somasAcA_OK(a->esq);
        b->dir = somasAcA_OK(a->dir);
    }
    if (a == NULL)
        b = NULL;
    return *res;
}

ABin somasAcA(ABin a)
{   // Remove unused b
    if (a != NULL)
    {
        a->valor = getsums(a);
        a->esq = somasAcA(a->esq);
        a->dir = somasAcA(a->dir);
    }
    return a;
}

static void print_postorder(ABin node)
{
    if (node != 0)
    {
        print_postorder(node->esq);
        print_postorder(node->dir);
        printf("Valor = %d\n", node->valor);
    }
}

static void print_tree(const char *tag, ABin node)
{
    printf("Tree: %s\n", tag);
    print_postorder(node);
}

static void free_tree(ABin node)
{
    if (node != 0)
    {
        free_tree(node->esq);
        free_tree(node->dir);
        free(node);
    }
}

int main(void)
{
    ABin root = newABin(3, 0, 0);
    ABin esq = newABin(1, 0, 0);
    ABin dir = newABin(2, 0, 0);
    root->esq = esq;
    root->dir = dir;

    print_tree("Before", root);

    ABin eval = somasAcA(root);
    assert(eval == root);

    print_tree("After", root);

    eval = somasAcA_OK(root);
    assert(eval != root);

    print_tree("Second time", root);

    free(root);
    free(esq);
    free(dir);
    free_tree(eval);
}

I created somasAcA_OK() from your working function, marginally cleaning it up. My somasAcA() is your ‘non-working’ function, somewhat cleaned up. I don’t think I significantly changed the functionality of either. Note that the tree building code doesn’t attempt to use a function to build it — you’ve not shown such a function. It creates three nodes and links them manually.

The code compiles cleanly under GCC 6.1.0 on Mac OS X 10.11.5 with the command line:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Werror abin.c -o abin
$

When run under valgrind, it gets a clean bill of health.

$ ./abin
Tree: Before
Valor = 1
Valor = 2
Valor = 3
Tree: After
Valor = 1
Valor = 2
Valor = 6
Tree: Second time
Valor = 1
Valor = 2
Valor = 6
$

On the basis of what I see, your second lot of code, the one that you claim fails, works correctly, but the one that you claim succeeds doesn’t actually do the addition (the last valor should be 9 on the second time).

I’m a bit dubious about the way your functions work. I’d expect the somasAcA() to be evaluating the sub-trees before summing the modified trees. That it works could be a side-effect of the minimal tree. Maybe you should be using:

ABin somasAcA(ABin a)
{
    if (a != NULL)
    {
        a->esq = somasAcA(a->esq);
        a->dir = somasAcA(a->dir);
        a->valor = getsums(a);
    }
    return a;
}

I’m not convinced that it needs to return a value, either, so with some collateral changes, you could use:

void somasAcA(ABin a)
{
    if (a != NULL)
    {
        somasAcA(a->esq);
        somasAcA(a->dir);
        a->valor = getsums(a);
    }
}

Extending the testing to more extensive trees is left as an exercise for someone with the correct tree-creation function code.

solved Function to turn a Binary Tree into the sums of all nodes below each node; segmentation fault if I don’t create a new binary tree [closed]