free () работает в отладчике, но не в режиме запуска - PullRequest
1 голос
/ 29 января 2020

Я пишу код для школьного проекта. Это дерево выражений, которое содержит цифры и операторы в инфиксной нотации. Древовидная структура

Дерево имеет следующую структуру:

typedef struct
{
    char the_operator;
    struct operand_node_tag *left_operand;
    struct operand_node_tag *right_operand;
} operator_node;

typedef struct operand_node_tag
{
    enum {operator_type, number_type} tree_node_type;
    union
    {
        operator_node the_operator_node;
        int the_number;
    };
} tree_node;

У меня есть функция, которая может динамически создавать узел оператора:

tree_node *create_expression(char op, tree_node *l, tree_node *r)
{
    // Dynamically reserve memory for a tree_node of type operator_type.
   tree_node *newTreeNode = malloc(sizeof(tree_node));
    if (newTreeNode == NULL)
    {           //Return NULL if there is no available memory.
    return NULL;
    }

    // Set the_operator to op, left_operand to l and right_operand to r
    newTreeNode->the_operator_node.the_operator = op;
    newTreeNode->the_operator_node.left_operand = l;
    newTreeNode->the_operator_node.right_operand = r;
    newTreeNode->tree_node_type = operator_type;

    // and return the tree_node
    return newTreeNode;
}

И функция, которая может динамически создавать числовой узел:

tree_node *create_number_node(int i)
{
    // Dynamically reserve memory for a tree_node of type number_type.
    tree_node *newTreeNode = malloc(sizeof(tree_node));
    if (newTreeNode == NULL) {                                              //Return NULL if there is no available memory.
        return NULL;
    }
    //Set the node type to number
    newTreeNode->tree_node_type = number_type;

    // Set the_number to i and return the tree_node
    newTreeNode->the_number = i;
    // and return the tree_node
    return newTreeNode;
}

Эти функции работают нормально для меня. Проблема возникает при освобождении выделенной памяти. Для которого я написал следующую функцию:

void free_expression_tree(tree_node **pnode)
    {
    // Free all dynamically reserved memory and set *pnode to NULL.
    if ((*pnode)->the_operator_node.left_operand && (*pnode)->tree_node_type == operator_type)
    {
    free_expression_tree(&(*pnode)->the_operator_node.left_operand);
    (*pnode)->the_operator_node.left_operand = NULL;
    }

    if ((*pnode)->the_operator_node.right_operand && (*pnode)->tree_node_type == operator_type)
    {
    free_expression_tree(&(*pnode)->the_operator_node.right_operand);
    (*pnode)->the_operator_node.right_operand = NULL;
    }

    printf("Free: ");
    if ((*pnode)->tree_node_type == operator_type)
        {
        printf("%c, ", (*pnode)->the_operator_node.the_operator);
        free(*pnode);
        printf("%d, \n", (*pnode)->the_operator_node.the_operator);
        }
    else
        {
        printf("%d, ", (*pnode)->the_number);
        free(*pnode);
        printf("%d, \n", (*pnode)->the_number);

    }
    }

Она проходит через данный узел и освобождает все узлы на более низких уровнях. Эта функция работает нормально в отладчике (G CC), давая в консоли следующий результат:

Free: 12, 3277136, 
Free: 40, 3277136, 
Free: 23, 3277136, 
Free: 3, 3296384, 
Free: -, -18, 
Free: /, -18, 
Free: 2, -17891602, 
Free: *, -18, 
Free: +, -18, 

Я печатаю число / оператор непосредственно перед и сразу после выполнения free ( ) функция. Кажется, здесь работает нормально.

Теперь вот тот же результат, но здесь я на самом деле запускаю .exe:

Free: 12, 3735888, 
Free: 40, 3735888, 
Free: 23, 3735888, 
Free: 3, 3763520, 
Free: -, -, 
Free: /, /, 
Free: 2, 2, 
Free: *, *, 
Free: +, +, 

Я предполагаю, что это как-то связано с компилятором настройки, но я не знаю, к чему. У меня отключены оптимизации.

У кого-нибудь из вас есть предложения?

Полный код: Main. c

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

#include "stack.h"
#include "tree.h"

int main(void)
{
    setbuf(stdout, NULL);
    tree_node *rootmin = create_expression('-', create_number_node(23), create_number_node(3));
    tree_node *rootdelen = create_expression('/', create_number_node(40), rootmin);
    tree_node *rootkeer = create_expression('*', rootdelen, create_number_node(2));
    tree_node *root = create_expression('+', create_number_node(12), rootkeer);
    printf("Infix:   ");
    print_tree_infix(root);
    printf("\n");

    printf("Postfix: ");
    print_tree_postfix(root);
    printf("\n");

    FILE *file = fopen("tree.graphviz", "w");
    if (file == NULL)
    {
        fprintf(stderr, "Error: Can not create file tree.graphviz.");
        return -1;
    }

    create_visual_graph_from_tree(root, file);
    printf("Open file tree.graphviz op https://stamm-wilbrandt.de/GraphvizFiddle/#.\n");

    free_expression_tree(&root);
    return 0;
}

tree. c:

#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
#include "stack.h"

tree_node *create_number_node(int i)
{
    // Dynamically reserve memory for a tree_node of type number_type.
    tree_node *newTreeNode = malloc(sizeof(tree_node));
    if (newTreeNode == NULL) {                                              //Return NULL if there is no available memory.
        return NULL;
    }
    //Set the node type to number
    newTreeNode->tree_node_type = number_type;

    // Set the_number to i and return the tree_node
    newTreeNode->the_number = i;
    // and return the tree_node
    return newTreeNode;
}

tree_node *create_expression(char op, tree_node *l, tree_node *r)
{
    // Dynamically reserve memory for a tree_node of type operator_type.
   tree_node *newTreeNode = malloc(sizeof(tree_node));
    if (newTreeNode == NULL)
    {           //Return NULL if there is no available memory.
    return NULL;
    }

    // Set the_operator to op, left_operand to l and right_operand to r
    newTreeNode->the_operator_node.the_operator = op;
    newTreeNode->the_operator_node.left_operand = l;
    newTreeNode->the_operator_node.right_operand = r;
    newTreeNode->tree_node_type = operator_type;

    // and return the tree_node
    return newTreeNode;
}

void free_expression_tree(tree_node **pnode)
    {
    // Free all dynamically reserved memory and set *pnode to NULL.
    if ((*pnode)->the_operator_node.left_operand && (*pnode)->tree_node_type == operator_type)
    {
    free_expression_tree(&(*pnode)->the_operator_node.left_operand);
    (*pnode)->the_operator_node.left_operand = NULL;
    }

    if ((*pnode)->the_operator_node.right_operand && (*pnode)->tree_node_type == operator_type)
    {
    free_expression_tree(&(*pnode)->the_operator_node.right_operand);
    (*pnode)->the_operator_node.right_operand = NULL;
    }

    printf("Free: ");
    if ((*pnode)->tree_node_type == operator_type)
        {
        printf("%c, ", (*pnode)->the_operator_node.the_operator);
        free(*pnode);
        printf("%c, \n", (*pnode)->the_operator_node.the_operator);
        }
    else
        {
        printf("%d, ", (*pnode)->the_number);
        free(*pnode);
        printf("%d, \n", (*pnode)->the_number);

    }
    }

void print_tree_postfix(const tree_node *node)
    {
    if (node)
    {
    print_tree_postfix(node->the_operator_node.left_operand);
    print_tree_postfix(node->the_operator_node.right_operand);

    if (node->tree_node_type == number_type)
        {
        printf("%d ", node->the_number);
        }
    else
        {
        printf("%c ", node->the_operator_node.the_operator);
        }
    }
    }

void print_tree_infix(const tree_node *node)
    {
    if (node)
    {
    if (node->the_operator_node.right_operand)
        {
        printf("(");
        }

    print_tree_infix(node->the_operator_node.left_operand);

    if (node->tree_node_type == number_type)
        {
        printf("%d", node->the_number);
        }
    else
        {
        printf("%c", node->the_operator_node.the_operator);
        }

    print_tree_infix(node->the_operator_node.right_operand);
    if (node->the_operator_node.left_operand)
        {
        printf(")");
        }
    }
    }
static void output_edge_to_visual_graph(char source, const tree_node *dest, FILE* file)
{
    fprintf(file, "  \"%c\" -> \"", source);
    switch (dest->tree_node_type)
    {
        case operator_type:
            fprintf(file, "%c", dest->the_operator_node.the_operator);
            break;
        case number_type:
            fprintf(file, "%d", dest->the_number);
            break;
    }
    fprintf(file, "\"\n");
}

static void output_node_to_visual_graph(const tree_node *node, FILE *file)
{
    if (node != NULL && node->tree_node_type == operator_type)
    {
        const operator_node *op = &(node->the_operator_node);
        if (op->left_operand != NULL && op->right_operand != NULL)
        {
            output_edge_to_visual_graph(op->the_operator, op->left_operand, file);
            output_edge_to_visual_graph(op->the_operator, op->right_operand, file);
            output_node_to_visual_graph(op->left_operand, file);
            output_node_to_visual_graph(op->right_operand, file);
        }
    }
}

void create_visual_graph_from_tree(const tree_node *root, FILE *file)
{
    if (file != NULL)
    {
        fprintf(file, "digraph G {\n");
        if (root != NULL) output_node_to_visual_graph(root, file);
        fprintf(file, "}\n");
    }
}

tree.h:

#ifndef TREE_H_
#define TREE_H_

typedef struct
{
    char the_operator;
    struct operand_node_tag *left_operand;
    struct operand_node_tag *right_operand;
} operator_node;

typedef struct operand_node_tag
{
    enum {operator_type, number_type} tree_node_type;
    union
    {
        operator_node the_operator_node;
        int the_number;
    };
} tree_node;

tree_node *create_number_node(int i);
tree_node *create_expression(char op, tree_node *l, tree_node *r);
void free_expression_tree(tree_node **pnode);
// frees all dynamically reserved memory and sets *pnode to NULL.

void print_tree_infix(const tree_node *node);
void print_tree_postfix(const tree_node *node);
void create_visual_graph_from_tree(const tree_node *root, FILE *file);

#endif /* TREE_H_ */

1 Ответ

2 голосов
/ 29 января 2020

За вами непосредственно следует

free(*pnode);

, например,

printf("%d, \n", (*pnode)->the_operator_node.the_operator);

Во втором выражении вы разыменовываете указатель, который вы только что передали free, поэтому память, в которой находится указатель указатель на больше не принадлежит вашей программе, и любая попытка разыменования указателя приведет к неопределенному поведению .

Вы просто не сможете использовать память, если она был свободен.

Решение этой проблемы состоит в том, чтобы не иметь этот второй printf вызов после вызова free, тем более что он будет печатать только то, что печатает первый вызов printf.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...