Программа не работает при смене функций местами

250
03 ноября 2021, 05:10

Почему-то программа крашится на 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;
}
Answer 1
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 инициализаторы по умолчанию и при этом еще и ручками написан явный старомодный список инициализации в конструкторе. Для пущей надежности?

READ ALSO
Задача на проверку последовательности

Задача на проверку последовательности

Я не могу понять что не так с кодом, можете помочь дописать его

96
Конвертирование типов long to int*

Конвертирование типов long to int*

Вопрос нубский, потому что питонистИмеется функция в хедере через extern C

242
Не работает вывод в файл в Visual studio 2019

Не работает вывод в файл в Visual studio 2019

Я пробовал запускать в visual 2019 но он не выводит в файл, я попробовал запустить в visual 2010 и dev cpp но там выводились цифры которые не как не относятся...

224