Почему-то программа крашится на scanf'е, выдаёт ошибку malloc_consolidate() invalid chunk size. Но если я поставлю функцию game_logic () в main после остальных, то всё будет работать исправно. (Delete вместо одного из free - уже сменил) Bin-tree.hpp:
///@file
#ifndef INCLUDE_TREE_H
#define INCLUDE_TREE_H
#include <iostream>
#include <stdlib.h>
#include <cstring>
#define $p getchar()
///@brief Enum with error codes for using my binary tree
enum ERR_CODE
{
OK = 0,
ALLOC_ERROR = 1,
IS_NOT_FREE = 2,
NOT_EXIST = 3,
NOT_LEAF = 4
};
///@brief Template class tree
template <typename T>
class Tree_t
{
public:
///@brief Node struct
struct Node_t
{
T data = 0;
Node_t *right = nullptr;
Node_t *left = nullptr;
Node_t (): right (nullptr), left (nullptr), data (0)
{};
} *head;
///@brief Constructor of Tree_t
Tree_t ()
{
head = new Node_t;
}
///@brief Destructor of Tree_t
~Tree_t ()
{
free_tree (head);
}
///@brief Function sets data to node
///@return OK if data was set or NOT_EXIST if node doesn't exist
ERR_CODE set_data (Node_t *node, T data)
{
if (!node) return NOT_EXIST;
node -> data = data;
return OK;
}
///@brief Function creates a right descedant
///@return OK if descedant was created, NOT_EXIST if node doesn't exist, IS_NOT_FREE if descedant was created before
ERR_CODE make_right (Node_t *node, T data)
{
if (!node) return NOT_EXIST;
if (node -> right) return IS_NOT_FREE;
node -> right = new Node_t;
node -> right -> data = data;
return OK;
}
///@brief Function creates a left descedant
///@return OK if descedant was created, NOT_EXIST if node doesn't exist, IS_NOT_FREE if descedant was created before
ERR_CODE make_left (Node_t *node, T data)
{
if (!node) return NOT_EXIST;
if (node -> left) return IS_NOT_FREE;
node -> left = new Node_t;
node -> left -> data = data;
return OK;
}
///@brief Delets a leaf
///@return OK if leaf was deletead, NOT_EXIST if node doesn't exist, NOT_LEAF if node is not leaf
ERR_CODE delete_leaf (Node_t **node)
{
if (!node) return NOT_EXIST;
if ((*node) -> right || (*node) -> left) return NOT_LEAF;
free (*node);
*node = nullptr;
}
///@brief VIRTUAL function for definition of nodes for dump
virtual void define_for_draw (FILE* stream, Node_t *node, bool dump)
{
fprintf (stream, "\"tree_node%p\" [label = \"", node);
write_data (stream, node -> data);
if (dump)
fprintf (stream," \n Address: %p\n Left: %p \n Right: %p", node, node -> left, node -> right);
fprintf (stream,"\"]\n");
if (node -> left)
{
define_for_draw (stream, node -> left, dump);
}
if (node -> right)
{
define_for_draw (stream, node -> right, dump);
}
}
///@brief VIRTUAL function for drawing of nodes
virtual void draw_nodes (FILE* stream, Node_t *node)
{
fprintf (stream, "\"tree_node%p\"\n", node);
if (node -> left)
{
fprintf (stream,"\"tree_node%p\" -> ", node);
draw_nodes (stream, node -> left);
}
if (node -> right)
{
fprintf (stream,"\"tree_node%p\" -> ", node);
draw_nodes (stream, node -> right);
}
}
///@brief dump of tree including only data
///@note Use "open" as an arguement for instant opening of png file
void draw ()
{
FILE* stream = fopen ("Tree_draw.dot", "w");
fprintf (stream, "digraph Tree{\n");
define_for_draw (stream, head, false);
draw_nodes (stream, head);
fprintf (stream,"\n}");
fclose (stream);
system ("dot -Tpng Tree_draw.dot -o tree_draw.png");
}
void draw (char* arg)
{
draw ();
if ( strcmp (arg, "open") == 0 )
system ("xdg-open tree_draw.png");
}
///@brief dump of tree including: data, address of node and addresses of children
///@note Use "open" as an arguement for instant opening of png file
void dump ()
{
FILE* stream = fopen ("Tree_dump.dot", "w");
fprintf (stream, "digraph Tree{\n");
define_for_draw (stream, head, true);
draw_nodes (stream, head);
fprintf (stream,"\n}");
fclose (stream);
system ("dot -Tpng Tree_dump.dot -o tree_dump.png");
}
void dump (char* arg)
{
dump ();
if ( strcmp (arg, "open") == 0 )
system ("xdg-open tree_dump.png");
}
protected:
///@brief A function for destructor... and btw it's private so it's NOT UR BUSINESS
void free_tree (Node_t *tree)
{
if (tree)
{
free_tree (tree -> left );
free_tree (tree -> right);
free (tree);
}
}
//-----------------------------------------------------------------------------------------------------
//Overloads of print function for dumping or drawing
//-----------------------------------------------------------------------------------------------------
///@brief Overloads of print function for dumping or drawing
void write_data (FILE* stream, const int &value)
{
fprintf (stream, "%d", value);
}
void write_data (FILE* stream, const unsigned int &value)
{
fprintf (stream, "%u", value);
}
void write_data (FILE* stream, const long &value)
{
fprintf (stream, "%ld", value);
}
void write_data (FILE* stream, const unsigned long &value)
{
fprintf (stream, "%lu", value);
}
void write_data (FILE* stream, const long long &value)
{
fprintf (stream, "%lld", value);
}
void write_data (FILE* stream, const unsigned long long &value)
{
fprintf (stream, "%llu", value);
}
void write_data (FILE* stream, const char &value)
{
fprintf (stream, "%c", value);
}
void write_data (FILE* stream, char* value)
{
fprintf (stream, "%s", value);
}
void write_data (FILE* stream, const float &value)
{
fprintf (stream, "%f", value);
}
void write_data (FILE* stream, const double &value)
{
fprintf (stream, "%lf", value);
}
};
#endif
Akinator:
#include "bin-tree.hpp"
#include <cassert>
static const int BUFSIZE = 256;
char userInput[BUFSIZE] = "";
class Akinator_tree : public Tree_t<char*>
{
char symb = 0;
int read_count = 0;
char buf[BUFSIZE] = "";
bool YES_flag = false;
void read_undertree (FILE* stream, Node_t *node)
{
assert (stream);
assert (node);
fscanf (stream," %*[{' ] ");
fscanf (stream,"%[^'{}]%n", buf, &read_count);
node -> data = (char*) calloc (read_count+1, sizeof (char));
strcpy (node -> data, buf);
fscanf (stream,"' ");
fscanf (stream, " %c ", &symb);
switch (symb)
{
case '{': make_left (node, (char*)""); read_undertree (stream, node -> left); break;
case '}': return; break;
default : fprintf (stderr, "Wrong syntax. Waited for '{' or '}'"); abort(); break;
}
fscanf (stream, " %c ", &symb);
switch (symb)
{
case '{': make_right (node, (char*)""); read_undertree (stream, node -> right); break;
case '}': return; break;
default : fprintf (stderr, "Wrong syntax. Waited for '{' or '}'"); abort(); break;
}
fscanf (stream, " %c ", &symb);
switch (symb)
{
case '{': fprintf (stderr, "Wrong syntax. Too much descedants (node can have only 2)"); abort(); break;
case '}': return; break;
default : fprintf (stderr, "Wrong syntax. Waited for '{' or '}'"); abort(); break;
}
}
void draw_nodes (FILE* stream, Node_t *node) override
{
if (node != head)
{
fprintf (stream, "\"tree_node%p\"\n", node);
if (YES_flag)
fprintf (stream, "[label = \"YES\", color = \"blue\"]");
else
fprintf (stream, "[label = \"NO\", color = \"red\"]");
}
if (node -> left)
{
fprintf (stream,"\"tree_node%p\" -> ", node);
YES_flag = false;
draw_nodes (stream, node -> left);
}
if (node -> right)
{
fprintf (stream,"\"tree_node%p\" -> ", node);
YES_flag = true;
draw_nodes (stream, node -> right);
}
}
public:
void read_tree (char* input_file)
{
FILE* stream = fopen (input_file, "r");
assert (stream);
read_undertree (stream, head);
fclose (stream);
}
void write_undertree (FILE* stream, Node_t *node)
{
assert (stream);
assert (node);
fprintf (stream, "{ '");
write_data(stream, node -> data);
fprintf (stream, "' ");
if (node -> left)
write_undertree (stream, node -> left);
if (node -> right)
write_undertree (stream, node -> right);
fprintf (stream, "}");
}
friend void go_lower_and_ask (Akinator_tree tree, Akinator_tree::Node_t *node);
};
void go_lower_and_ask (Akinator_tree tree, Akinator_tree::Node_t *node)
{
if ( node -> right && node -> left )
{
tree.write_data (stdout, node -> data);
printf ("?\n");
scanf ("%s", userInput);
if ( ! strcmp ("да", userInput) || ! strcmp ("yes", userInput) )
go_lower_and_ask (tree, node -> right);
else if ( ! strcmp ("нет", userInput) || ! strcmp ("no", userInput) )
go_lower_and_ask (tree, node -> left);
else
{
fprintf (stderr, "Wrong answer, try again\n");
go_lower_and_ask (tree, node);
}
}
else
printf ("%s", node -> data);
}
void game_logic (Akinator_tree tree)
{
printf ("Здравствуй, мой друг. Сыграем в акинатора? Предупреждаю, обыграть меня ооочень непростоб хе-хе;)\n");
scanf ("%s", userInput);
if ( ! strcmp ("да", userInput) || ! strcmp ("yes", userInput) )
go_lower_and_ask (tree, tree.head);
else if ( ! strcmp ("нет", userInput) || ! strcmp ("no", userInput) )
return;
else
{
fprintf (stderr, "Wrong answer, try again\n");
game_logic(tree);
}
}
int main ()
{
setlocale (LC_ALL, "rus");
Akinator_tree tree;
tree.read_tree((char*)"tree-base.txt");
tree.draw ((char*)"open");
FILE* stream = fopen ("out.txt", "w");
game_logic (tree);
tree.write_undertree (stream, tree.head);
return 0;
}
void game_logic (Akinator_tree tree)
void go_lower_and_ask (Akinator_tree tree, Akinator_tree::Node_t *node)
Akinator_tree
передается в эти функции по значению (почему-то), но Правило Трех в классе Akinator_tree
не соблюдено. Дальше можно не смотреть.
Также не ясно, зачем в классе Node_t
у вас использованы C++11 инициализаторы по умолчанию и при этом еще и ручками написан явный старомодный список инициализации в конструкторе. Для пущей надежности?
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Я не могу понять что не так с кодом, можете помочь дописать его
Вопрос нубский, потому что питонистИмеется функция в хедере через extern C
Я пробовал запускать в visual 2019 но он не выводит в файл, я попробовал запустить в visual 2010 и dev cpp но там выводились цифры которые не как не относятся...