来自重新定义的<<<<< c ++中的运算符

时间:2010-10-31 20:04:05

标签: c++ file-io operator-overloading corruption

我遇到了一个运行时错误,我无法解决这个问题。我的程序几乎完成了我想要的程序,但是有一些损坏的字符打印出来作为胡言乱语。该程序应该采用代表树木森林的文本文件,构建树木森林,然后穿过森林将其打印出来。 树可以任意大,每个节点可以有任意多个子节点。林在文本文件中表示为:

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

进程返回0(0x0)执行时间:0.092秒 按任意键继续。

正如你所看到的,输出非常接近它应该是什么,但是它们包含在ForestNodes中的一些字符或标签已经损坏,我不能为我的生活找出原因。任何帮助都会非常感激,你会被我视为男人之中的神。

1 个答案:

答案 0 :(得分:3)

据我所知,您的节点包含指向函数bar中的本地缓冲区inputHelper()的指针。在调用getTag()后立即打印setTag()(已注释掉)的结果时,缓冲区仍然有效。但是,只要函数返回,您的代码就会导致未定义的行为,因为您指的是堆栈上某些无效的位置。

您是否考虑过使用std::string代替char缓冲区和char*std::string的自动内存管理和复制语义将解决您的问题。

编辑:输出乱码的原因是较低的堆栈帧被其他一些函数调用覆盖。树中的Deper节点碰巧引用更远的存储器并且不太可能被覆盖,这就是它们的值被正确输出的原因。