2010-10-31 62 views
0

我遇到了一個運行時錯誤,我不能爲我的生活弄清楚。我的程序幾乎做到了我想要的內容,但是有些字符被打亂成亂碼。該程序應該包含代表樹木森林的文本文件,構建樹木森林,然後遍歷森林將其打印出來。 該樹可以是任意大的,並且每個節點可以任意地很多孩子。森林在文本文件中這樣表示:在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 

進程返回0(爲0x0)執行時間:0.092小號 按任意鍵繼續。

正如你所看到的,輸出非常接近它應該是的,但是一些字符或標籤,因爲它們被包含在ForestNodes中被破壞了,我不能爲了我的生活找出原因。任何幫助將不勝感激,你會被我視爲男人之神。

+1

TLDR嘗試製作一個指出問題的簡短示例。順便提一下,當你嘗試製作一個時,你有一個很難找到錯誤的機會。 – 2010-10-31 20:08:23

回答

3

據我所知,您的節點包含指向函數inputHelper()中的本地緩衝區bar的指針。當你打電話給setTag()後立即打印getTag()(註釋掉)的結果時,緩衝區仍然有效。但是,只要函數返回,您的代碼就會導致未定義的行爲,因爲您指的是堆棧中某個無效的位置。

您是否考慮過使用std::string而不是char緩衝區和char*std::string的自動內存管理和複製語義將解決您的問題。

編輯:輸出亂碼是由較低的堆棧幀被其他函數調用寫入的事實解釋的。樹中的Deper節點碰巧指的是更遠的內存並且不太可能被覆蓋,這就是爲什麼它們的值被正確輸出的原因。

+0

setTag()應該通過值來引用參數,而不是引用。那麼,在函數結束後,如果堆中的節點將其標記設置爲該值,那麼bar的內存是否會被釋放? – joedillian 2010-10-31 20:17:40

+0

啊。這就說得通了。謝謝,我會嘗試使用字符串類重寫。 – joedillian 2010-10-31 20:22:24

+0

@ joedillian:是的,它確實很重要!你正在傳遞一個*指針*值。如果指針引用的內存無效,那麼您的標籤將不再可用。 – 2010-10-31 20:24:14