Search code examples
cpointersyacc

Pointer changes value without reason?


I have to do this project on Flex/Yacc, where I must calculate the Abstract Syntax Tree of an Insiemistic expression. But the real problem is within the C code.

I've made this function, that creates a node:

node_t * createNode(node_content_t nodecontent, int nodetype){
    node_t *newNode = (node_t *) malloc(sizeof(node_t * ));
    if(nodetype == 0){
        newNode->content = (node_content_t)strdup(nodecontent.string);
    }
    else
        newNode->content = nodecontent;
    newNode->type = nodetype;

    newNode->leftChild = NULL;
    newNode->rightChild = NULL;
    printf("Right Child in createNode: %p\n", newNode->rightChild);
    return newNode;
}

As you can see, left and right child are both initialized to null. But when i try to print the pointer value of the right child out of the function, it changes value(tipically to 0x23 or 0x53), leading to a segmentation fault.

node_t and node_content_t are defined as follows

typedef union{
        char* string;
        char singleletter;
    }node_content_t;


    typedef struct node node_t;
    struct node{
        node_content_t content;
        int type; //0 for string, 1 for char
        node_t *leftChild;
        node_t *rightChild;
    };

When i tried to print the pointer in createNode, it resulted 0x0, i printed it in this function printNode, that should print the entire tree:

void printNode(node_t *n, size_t indent) {
    
    char *indentation = malloc(sizeof(char) * indent);
    for (size_t i = 0; i < indent; ++i) {
        indentation[i] = ' ';
    }
    printf("LeftChild: %p\n", n->leftChild);
    printf("RightChild: %p\n", n->rightChild);
    switch (n->type) {
        case 0: printf("%s%s\n", indentation, n->content); break;
        case 1: printf("%s%c\n", indentation, n->content); break;
    }
    if (n->leftChild != NULL){
        printNode(n->leftChild, indent+2);
    }
    if (n->rightChild != NULL){
        printf("RightChild: %p\n", n->rightChild); //there
        printNode(n->rightChild, indent+2);
    }
    printf("Non ci sono figli\n");

}

And as i said, the value change, so the function doesn't work, any ideas? I don't modify the value of rightChild if not in the function addChild:

void addChild(node_t *parent, node_t *child) {
    printf("Addchild\n");
    printf("Right Child in createNode: %p\n", parent->rightChild);
    if(parent->leftChild == NULL)
        parent->leftChild = child;
    else if(parent->rightChild == NULL && strcmp(parent->content.string, "co") != 0 ){
        parent-> rightChild = child;
        printf("Aggiunto figlio destro\nContent: %c\nType: %d\n", child->content, child->type);
    }
    else
        printf("Error during child adding\n");
}

Solution

  • Problem 1:

    node_t *newNode = (node_t *) malloc(sizeof(node_t * ));
    
    1. This allocates enough space for node_t *; not the node_t struct you intend.
    2. Casting is unnecessary (and could be harmful.)
    3. Better to use the variable's name rather than its type (reducing future maintenance.)
    4. malloc() can fail. Get used to checking return values. Make it a habit!
    node_t *newNode = malloc( sizeof *newNode ); // cleaner
    if( newNode == NULL ) { /* handle error condition */ }
    

    Problem 2:

    void printNode(node_t *n, size_t indent) {
        
        char *indentation = malloc(sizeof(char) * indent); // <== never free'd
        for (size_t i = 0; i < indent; ++i) { // unnecessary...
            indentation[i] = ' ';
        }
        printf("LeftChild: %p\n", n->leftChild);
        printf("RightChild: %p\n", n->rightChild);
        switch (n->type) {
            case 0: printf("%s%s\n", indentation, n->content); break;
            case 1: printf("%s%c\n", indentation, n->content); break;
        }
    
    1. indentation is allocated each time this function is called, and it is never free()'d.
      Memory leak (hastening the occurrence of allocation failing.)
    2. indentation is NOT null terminated and must not be treated as a C string.

    Get rid of the lines performing the allocation and utilise the capabilities of printf(). Eg:

    printf( "%*s%s\n", indent, "", n->content ); break;
    

    %*s gets the field width specifier from the next parameter, in this case indent. It then gets the string to be printed in a field that wide, in this case "". The result is a prefix of the desired number of spaces on each line.