重新定义的 << 的奇数输出c++ 中的运算符
我遇到了一个运行时错误,我一生都无法弄清楚。我的程序几乎完成了我想要的功能,但是有一些损坏的字符打印出来是乱码。该程序应该接收一个代表树木森林的文本文件,构建树木森林,然后遍历森林将其打印出来。 树可以任意大,每个节点可以有任意多个子节点。森林在文本文件中表示如下:
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;
}
endif
(文件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
Process returned 0 (0x0)execution time : 0.092 s 按任意键继续。
正如您所看到的,输出非常接近应有的结果,但是 ForestNode 中包含的某些字符或标签已损坏,我一生都无法弄清楚原因。任何帮助将不胜感激,我将视你为人间神。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
据我所知,您的节点在函数
inputHelper()
中包含指向本地缓冲区bar
的指针。当您在调用setTag()
之后立即打印getTag()
(已注释掉)的结果时,缓冲区仍然有效。但是,一旦函数返回,您的代码就会导致未定义的行为,因为您引用的是堆栈上不再有效的某个位置。您是否考虑过使用
std::string
而不是char
缓冲区和char*
?std::string
的自动内存管理和复制语义将解决您的问题。编辑:输出乱码的原因是较低的堆栈帧被其他一些函数调用覆盖。树中的 Deper 节点恰好引用了距离较远且不太可能被覆盖的内存,这就是它们的值能够正确输出的原因。
As far as I can tell, your nodes contain pointers to a local buffer
bar
in functioninputHelper()
. When you print the result ofgetTag()
(commented out) right after the call tosetTag()
, the buffer is still valid. However, as soon as the function returns, your code results in undefined behavior because you are referring to some location on the stack that is not valid anymore.Have you considered using
std::string
instead ofchar
buffers andchar*
? The automatic memory management and copy semantics ofstd::string
will solve your problem.Edit: the output gibberish is explained by the fact that the lower stack frames are written over by some other function calls. Deper nodes in the trees happen to refer to memory that is further away and less likely to be overwritten, which is why their values are output properly.