Нечетный вывод переопределенного оператора << в c ++ - PullRequest
0 голосов
/ 31 октября 2010

У меня ошибка во время выполнения, которую я не могу понять на всю жизнь.Моя программа почти делает то, что я хочу, но есть некоторые испорченные символы, которые печатаются как бред.Предполагается, что программа принимает текстовый файл, представляющий лес из деревьев, строит лес из деревьев, затем пересекает лес, чтобы распечатать его так, как он был взят. Дерево может быть произвольно большим, и каждый узел может иметь произвольно многодети.Лес представлен в текстовом файле следующим образом:

a  
  b  
    c  
  d  
    e  
    z  
f  
  g  
    h  
  i  
    j  

и будет преобразован в следующий лес из двух деревьев:

    a     
   / \  
  b   d  
 /   / \  
c   e   z  

    f      
   / \  
  g   i  
 /   /  
h   j  

Закомментированные строки в коде являются реликтами, которые остаютсяс того момента, когда я проверял, чтобы убедиться, что файл читается правильно и что создаваемые мной узлы были правильно помечены и на них указаны.

Мой код выглядит следующим образом:

(файловый узел.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;
}

IЯ использую следующий текстовый файл:

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 с Нажмите любую клавишу для продолжения.

Как видите, выходные данные очень близки к тому, что должно быть, однако некоторые символы или теги, содержащиеся в лесных узлах, повреждены, и я не могу понять, почему.Любая помощь будет принята с благодарностью, и я буду считать вас богом среди людей.

1 Ответ

3 голосов
/ 31 октября 2010

Насколько я могу судить, ваши узлы содержат указатели на локальный буфер bar в функции inputHelper(). Когда вы выводите результат getTag() (закомментированный) сразу после вызова setTag(), буфер остается действительным. Однако, как только функция возвращается, ваш код приводит к неопределенному поведению , потому что вы ссылаетесь на какое-то место в стеке, которое больше не является допустимым.

Рассматривали ли вы использование std::string вместо char буферов и char*? Автоматическое управление памятью и семантика копирования std::string решат вашу проблему.

Редактировать : выходной тарабарщина объясняется тем, что кадры нижнего стека перезаписываются некоторыми другими вызовами функций. Случайные узлы в деревьях ссылаются на память, которая находится дальше и реже перезаписывается, поэтому их значения выводятся правильно.

...