重新定义的 << 的奇数输出c++ 中的运算符

发布于 2024-09-29 15:09:28 字数 7402 浏览 5 评论 0 原文

我遇到了一个运行时错误,我一生都无法弄清楚。我的程序几乎完成了我想要的功能,但是有一些损坏的字符打印出来是乱码。该程序应该接收一个代表树木森林的文本文件,构建树木森林,然后遍历森林将其打印出来。 树可以任意大,每个节点可以有任意多个子节点。森林在文本文件中表示如下:

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 中包含的某些字符或标签已损坏,我一生都无法弄清楚原因。任何帮助将不胜感激,我将视你为人间神。

I am having a runtime error that I can not for the life of me figure out. My program almost does what I want it to, but there are some corrupted characters that print out as gibberish. The program is supposed to take in a text file that represents a forest of trees, build the forest of trees, then traverse the forest to print it out as it was taken in.
The tree can be arbitrarily large and each node can have arbitrarily many children. The forest is represented in the textfile as such:

a  
  b  
    c  
  d  
    e  
    z  
f  
  g  
    h  
  i  
    j  

and would translate to the following forest of two trees:

    a     
   / \  
  b   d  
 /   / \  
c   e   z  

    f      
   / \  
  g   i  
 /   /  
h   j  

The commented out lines in the code are relics that remain from when I was testing to make sure that the file was being read correctly and that the nodes I was creating were properly tagged and pointed to.

My code is as follows:

(file 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

(file 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

(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;
}

I am using the following text file:

a
  z
    c
      d
    e
      f
  g
    h
  i
    y
x
  w
    m
      n
    o
      p
  q
    r
  s
    t

And my output is as follows:

└@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
Press any key to continue.

As you can see, the output is very close to what it should be, however some of the characters, or tags as they are contained within ForestNodes are corrupted, and I cannot for the life of me figure out why. Any help would be greatly appreciated, and you would be regarded by me as a god among men.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

始于初秋 2024-10-06 15:09:28

据我所知,您的节点在函数 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 function inputHelper(). When you print the result of getTag() (commented out) right after the call to setTag(), 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 of char buffers and char*? The automatic memory management and copy semantics of std::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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文