我遇到了一个运行时错误,我无法解决这个问题。我的程序几乎完成了我想要的程序,但是有一些损坏的字符打印出来作为胡言乱语。该程序应该采用代表树木森林的文本文件,构建树木森林,然后穿过森林将其打印出来。 树可以任意大,每个节点可以有任意多个子节点。林在文本文件中表示为:
a
b
c
d
e
z
f
g
h
i
j
并将转换为以下两棵树的森林:
a
/ \
b d
/ / \
c e z
f
/ \
g i
/ /
h j
代码中注释掉的行是我在测试时保留的文件,以确保正确读取文件,并且我正在创建的节点已正确标记并指向。
我的代码如下:
(文件node.h)
#ifndef NODE_H
#define NODE_H
template<typename NODETYPE> class Forest;
template<typename NODETYPE> class ForestNode
{
friend class Forest<NODETYPE>;
public:
ForestNode();
NODETYPE getTag() const;
ForestNode<NODETYPE> * getLeftChild() const;
ForestNode<NODETYPE> * getSibling() const;
void setTag(NODETYPE);
void setLeftChild(ForestNode<NODETYPE>*);
void setSibling(ForestNode<NODETYPE>*);
private:
NODETYPE tag;
ForestNode<NODETYPE> * leftChild;
ForestNode<NODETYPE> * sibling;
};
template<typename NODETYPE> ForestNode<NODETYPE>::ForestNode()
: tag(0), leftChild(NULL), sibling(NULL)
{
}
template<typename NODETYPE> NODETYPE ForestNode<NODETYPE>::getTag() const
{
return tag;
}
template<typename NODETYPE> ForestNode<NODETYPE>* ForestNode<NODETYPE>::getLeftChild() const
{
return leftChild;
}
template<typename NODETYPE> ForestNode<NODETYPE>* ForestNode<NODETYPE>::getSibling() const
{
return sibling;
}
template<typename NODETYPE> void ForestNode<NODETYPE>::setTag(NODETYPE info)
{
this->tag = info;
}
template<typename NODETYPE> void ForestNode<NODETYPE>::setLeftChild(ForestNode<NODETYPE>* info)
{
leftChild = info;
}
template<typename NODETYPE> void ForestNode<NODETYPE>::setSibling(ForestNode<NODETYPE>* info)
{
sibling = info;
}
#endif // NODE_H
(文件forest.h)
#ifndef FOREST_H
#define FOREST_H
#include <iostream>
#include <cstdlib>
#include <string>
#include "node.h"
using namespace std;
template<typename NODETYPE> class Forest
{
template<NODETYPE> friend ostream& operator<<(ostream& output, const Forest<NODETYPE>& f1);
template<NODETYPE> friend void outputHelper(ostream& output, const ForestNode<NODETYPE>& currentNode, int depth);
friend void inputHelper(istream& file, int previousDepth, ForestNode<char*>& previousNode, ForestNode<char*>* *nodeArray, int& nodeCount);
friend istream& operator>>(istream& file, Forest<char*>& f1);
public:
Forest();
Forest( const Forest& otherForest);
void nodes(int&) const;
ForestNode<NODETYPE> * root;
};
template<typename NODETYPE>ostream& operator<<(ostream& output, const Forest<NODETYPE>& f1)
{
int depth = 0;
output << f1.root->getTag();
outputHelper(output, f1.root, depth);
return output;
}
void outputHelper(ostream& output, const ForestNode<char*> *currentNode, int depth)
{
for(int i = 0; i < depth; i++)
{
output << ' ' << ' ';
}
output << currentNode->getTag();
output << endl;
if(currentNode->getLeftChild() != NULL)
{
outputHelper(output, currentNode->getLeftChild(), depth+1);
}
if(currentNode->getSibling() != NULL)
{
outputHelper(output, currentNode->getSibling(), depth);
}
}
void inputHelper(istream& file, int previousDepth, ForestNode<char*>* previousNode, ForestNode<char*> ** nodeArray, int& nodeCount)
{
int spaceCounter = 0;
while(file.peek() == ' ')
{
spaceCounter++;
file.ignore(1);
}
ForestNode<char*>* currentNode = new ForestNode<char*>();
char bar[100];
file.getline(bar, 100);
// cout << bar << endl;
currentNode->setTag(bar);
// cout << currentNode->getTag();
if(spaceCounter/2 < previousDepth)
{
for(int i = (spaceCounter/2)+1; i < nodeCount; i++)
{
nodeArray[i] = NULL;
}
}
cout << "array:";
for(int i = 0; i < spaceCounter/2; i++)
{
cout << nodeArray[i]->getTag();
}
// cout << endl;
// cout << spaceCounter/2 << ':';
if(spaceCounter/2 == previousDepth+1)
{
previousNode->setLeftChild(currentNode);
// cout << "i'm a child:" << previousNode->getLeftChild()->getTag() << " and my parent is:" << nodeArray[(spaceCounter/2)-1]->getTag();
nodeArray[spaceCounter/2] = currentNode;
}
else
{
if(!(nodeArray[spaceCounter/2] == NULL))
{
nodeArray[spaceCounter/2]->setSibling(currentNode);
// cout << "I'm a sibling:" << nodeArray[spaceCounter/2]->getSibling()->getTag() << " and my older sibling is:" << nodeArray[spaceCounter/2]->getTag();
nodeArray[spaceCounter/2] = currentNode;
}
}
// cout << endl;
// cout << currentNode->getTag();
if(!file.eof())
{
inputHelper(file, spaceCounter/2, currentNode, nodeArray, nodeCount);
}
}
istream& operator>>(istream& file, Forest<char*>& f1)
{
int charCount = 0;
int nodeCount = 0;
file.seekg(0, ios_base::end);
charCount = file.tellg();
file.seekg(0, ios_base::beg);
for(int i=0; i <= charCount; i++)
{
// cout << i << ':' << file.peek() << endl;
if(file.peek() == '\n')
{
nodeCount++;
}
file.seekg(i);
}
file.seekg(0, ios_base::beg);
nodeCount = nodeCount/2;
nodeCount = nodeCount + 1;
ForestNode<char*>* forestNodeArray[nodeCount];//holds pointers to last node of depth i
char bar[100];
file.getline(bar, 100);
cout << bar << endl;
ForestNode<char*>* foo = new ForestNode<char*>();
f1.root = foo;
f1.root->setTag(bar);
forestNodeArray[0] = f1.root;
inputHelper(file, 0, f1.root, forestNodeArray, nodeCount);
return file;
}
(文件main.h)
#include <iostream>
#include <fstream>
#include "forest.h"
using namespace std;
int main()
{
Forest<char*> forest;
filebuf fb;
fb.open ("forest1.txt",ios::in);
istream is(&fb);
is >> forest;
fb.close();
cout << forest;
}
我使用以下文本文件:
a
z
c
d
e
f
g
h
i
y
x
w
m
n
o
p
q
r
s
t
我的输出如下:
└@GƒtF
░≥9
c
d
e
f
g
h
i
Eⁿ(
☺
L⌡(
m
n
o
p
q
r
s
t
进程返回0(0x0)执行时间:0.092秒 按任意键继续。
正如你所看到的,输出非常接近它应该是什么,但是它们包含在ForestNodes中的一些字符或标签已经损坏,我不能为我的生活找出原因。任何帮助都会非常感激,你会被我视为男人之中的神。
答案 0 :(得分:3)
据我所知,您的节点包含指向函数bar
中的本地缓冲区inputHelper()
的指针。在调用getTag()
后立即打印setTag()
(已注释掉)的结果时,缓冲区仍然有效。但是,只要函数返回,您的代码就会导致未定义的行为,因为您指的是堆栈上某些无效的位置。
您是否考虑过使用std::string
代替char
缓冲区和char*
? std::string
的自动内存管理和复制语义将解决您的问题。
编辑:输出乱码的原因是较低的堆栈帧被其他一些函数调用覆盖。树中的Deper节点碰巧引用更远的存储器并且不太可能被覆盖,这就是它们的值被正确输出的原因。