Я пишу код для школьного проекта. Это дерево выражений, которое содержит цифры и операторы в инфиксной нотации. Древовидная структура
Дерево имеет следующую структуру:
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_ */