Строковой дерева считывается не правильно
Помогите, пожалуйста, кто знает. Я уже несколько дней сижу с этой ошибкой и не могу понять что не так. По заданию нужно считать n-арное дерево из файла, но почему-то после считывания значения деревьев меняются на не понятные символы хотя во время выполнения функции значения все верные у всех поддеревьев. вот мой код:
#include <iostream>
#include <cstring>
#include <string>
#include "locale.h"
#include <fstream>
#include <vector>
using namespace std;
struct tnode
{
char* key;
int id = 0;
int status = 0;
int count = 0;
int lvl = 0;
vector <struct tnode*> vect;
struct tnode* parent;
};
struct tnode* addtree(tnode* tree, char* w, int tt, int tz, int id)
{
int d = 0;
while (d < tt - 1)
{
if(!tree->vect.empty())
if(tree->vect.back())
tree = tree->vect.back();
d++;
}
if (tt == 0)
{
tree->key = w;
tree->id = id;
tree->lvl = tt + 1;
return tree;
}
else
{
tnode* trer = new tnode;
trer->id = id;
trer->parent = tree;
trer->key = w;
trer->lvl = tt + 1;
tree->vect.push_back(trer);
tree->status = 1;
tree->count++;
int i = 0;
while (i < tt - 1)
{
if (tree->parent) tree = tree->parent;
i++;
}
return tree;
}
return tree;
}
int tt = 0;
int id = 0;
void deserialize(tnode*& root, FILE* fp)
{
setlocale(LC_ALL, "Russian");
char val[250];
char nik[259];
if (!fgets(val,200,fp))
{
printf("%s ", root->key);
return ;
}
int i = 0;
int b = 0;
while (i < 100)
{
if (val[i] == '.')
b++;
i++;
}
i = 0;
int d;
if (b > 0)
{
while (i < strlen(val))
{
if (val[b + i] != 0 && val[b + i] != ' ')
{
val[i] = val[b + i];
}
else
{
d = i;
val[i] = 0;
}
i++;
}
}
id++;
root = addtree(root, val, b, tt, id);
deserialize(root, fp);
}
int main()
{
setlocale(LC_ALL, "Russian");
tnode* tree = new tnode;
FILE* file = fopen("tree.txt", "r");
deserialize(tree, file);
puts(tree->key);
return 0;
}
вот текст файла tree.txt:
Ann
.Boris
..CAT
..Dora
...Eva
...Fred
..Gova
...Helmut
....Marta
.....Bred
.....Stiv
.....Jon
......Tom
...Nata
.Nina
Ответы (1 шт):
Я полностью переписал deserialize() функцию используя C++ стиль.
Структуру самого узла дерева tnode не менял, чтобы она осталась совместима с вашей программой, только добавил внутрь структуры деструктор ~tnode() - это функция для автоматической очистки ресурсов узла и всё его поддерево, всегда нужно очищать все ресурсы программы.
Также добавил dump() функцию, она выводит дерево в красивом виде в консоль.
Весь код ниже, включая примеры использования всех функций (с вашим входным файлом tree.txt):
#include <iostream>
#include <cstring>
#include <string>
#include "locale.h"
#include <fstream>
#include <vector>
#include <stdexcept>
#include <memory>
#include <tuple>
#include <functional>
#include <algorithm>
using namespace std;
#define LN { std::cout << __LINE__ << std::endl; }
struct tnode
{
char* key = 0;
int id = 0;
int status = 0;
int count = 0;
int lvl = 0;
vector <struct tnode*> vect;
struct tnode* parent = 0;
~tnode() {
if (key) delete[] key;
for (auto & e: vect)
if (e) delete e;
}
};
struct tnode* addtree(tnode* tree, char* w, int tt, int tz, int id)
{
int d = 0;
while (d < tt - 1)
{
if(!tree->vect.empty())
if(tree->vect.back())
tree = tree->vect.back();
d++;
}
if (tt == 0)
{
tree->key = w;
tree->id = id;
tree->lvl = tt + 1;
return tree;
}
else
{
tnode* trer = new tnode;
trer->id = id;
trer->parent = tree;
trer->key = w;
trer->lvl = tt + 1;
tree->vect.push_back(trer);
tree->status = 1;
tree->count++;
int i = 0;
while (i < tt - 1)
{
if (tree->parent) tree = tree->parent;
i++;
}
return tree;
}
return tree;
}
int tt = 0;
int id = 0;
tnode * deserialize(std::string const & file_name)
{
std::ifstream inf(file_name);
std::vector<std::string> lines;
std::string line;
while (std::getline(inf, line)) {
line.erase(0, line.find_first_not_of("\t\n\v\f\r ")); // left trim
line.erase(line.find_last_not_of("\t\n\v\f\r ") + 1); // right trim
if (line.empty())
continue;
lines.push_back(line);
}
std::function<std::tuple<size_t, std::unique_ptr<tnode>>(size_t, size_t)> drec;
drec = [&lines, &drec](size_t il, size_t offset){
if (il >= lines.size() || (offset > 0 && lines[il][offset - 1] != '.'))
return std::make_tuple(il, std::unique_ptr<tnode>());
if (offset > lines[il].length() || (offset > 0 && lines[il][offset - 1] != '.') || (offset < lines[il].length() && lines[il][offset] == '.'))
throw std::runtime_error("Wrong offset of node '" + lines[il] + "'! Should be " + std::to_string(offset));
auto node = std::make_unique<tnode>();
auto skey = lines[il].substr(offset);
node->key = new char[skey.length() + 1];
node->key[skey.length()] = 0;
std::copy(skey.begin(), skey.end(), node->key);
++il;
while (true) {
auto sres = drec(il, offset + 1);
il = std::get<0>(sres);
auto & child = std::get<1>(sres);
if (!child) break;
child->parent = node.get();
node->vect.push_back(child.release());
}
return std::make_tuple(il, std::move(node));
};
return std::get<1>(drec(0, 0)).release();
}
void dump(tnode const & node, std::string const & prefix = "", bool root = true, bool last = true) {
std::cout << prefix << (root ? "" : (last ? "\\-" : "|-")) << (node.key ? node.key : "") << std::endl;
for (size_t i = 0; i < node.vect.size(); ++i)
dump(*node.vect[i], prefix + (root ? "" : (last ? " " : "| ")), false, i + 1 >= node.vect.size());
}
int main()
{
try {
setlocale(LC_ALL, "Russian");
auto proot = deserialize("tree.txt");
dump(*proot);
delete proot;
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Вывод:
Ann
|-Boris
| |-CAT
| |-Dora
| | |-Eva
| | \-Fred
| \-Gova
| |-Helmut
| | \-Marta
| | |-Bred
| | |-Stiv
| | \-Jon
| | \-Tom
| \-Nata
\-Nina