【问题标题】:Segmentation Fault when using TinyXML recursively to generate General Tree?递归使用 TinyXML 生成通用树时出现分段错误?
【发布时间】:2016-11-06 13:19:30
【问题描述】:

我正在尝试使用 TinyXML 解析 XML 文件以构建通用树。我正在尝试递归地执行此操作。问题是,每当我这样做时,都会遇到分段错误。

这里是sn-p:

void buildTree() {
        // Loading XML file and getting rootNode
        string filename = "generalTree.xml";
        TiXmlDocument doc(filename);
        bool loadOkay = doc.LoadFile();
        if (!loadOkay) {
            cout << "Could not load file " << filename << endl;
            cout << "Error='" << doc.ErrorDesc() <<"'. Exiting.\n";
        }
        TiXmlNode* generalTreeNode = doc.FirstChild("GeneralTree");
        TiXmlNode* rootNode = generalTreeNode->FirstChild();
        int key = stoi(rootNode->ToElement()->Attribute("key"));
        Type data = rootNode->ToElement()->GetText();
        root = new TreeNode<Type>("General", key, data);
        // Populating the rest of the tree via recursive function
        recFunction(rootNode);
    }

这里是recFunction:

  void recFunction(TiXmlNode *node) {
        if(node->FirstChildElement() == NULL) {
            cout << "First child element is null" << endl;
        } else {
            int key = stoi(node->ToElement()->Attribute("key"));
            Type data = node->ToElement()->GetText();
            TreeNode<Type> *treeNode = new TreeNode<Type>("General", key, data);
            cout << "Right BEFORE recursive activates" << endl;
            return recFunction(node->FirstChild());
        }
        cout << "After recursiveness done" << endl;
        // After recursiveness is finished
        while(node->NextSibling() != NULL) {
            if(!node) {
                cout << "Node is null, breaking" << endl;
                break;
            }
            // Converting XML node to TreeNode
            cout << "DOING NODE TO ELEMENT" << endl;
            cout << node->ToText()->Value() << endl;
            cout << "Node is of type: " << typeid(node).name() << endl;
            cout << node->ToElement()->Attribute("key") << endl;
            cout << "DONE WITH NODE TO ELEMENT" << endl;
            int key = stoi(node->ToElement()->Attribute("key"));
            cout << "Key 1 is: " << key << endl;
            Type data = node->ToElement()->GetText();
            cout << "Data 1 is: " << data << endl;
            TreeNode<Type> *prev = new TreeNode<Type>("General", key, data);
            int key2 = stoi(node->NextSibling()->ToElement()->Attribute("key"));
            Type data2 = node->ToElement()->GetText();
            TreeNode<Type> *cur = new TreeNode<Type>("General", key2, data2);
            // Create linked list of siblings
            prev->setSibling(cur);
            node = node->NextSibling();
        }
        cout << "End of while loop reached" << endl;
    }

这里是 XML 文件:

<?xml version="1.0"?>
<GeneralTree>
    <Node key="1"> Genres
        <Node key="2">Thriller</Node>
        <Node key="3">Action</Node>
        <Node key="4">Romance
            <Node key="7">A Walk To Remember</Node>
            <Node key="8">The Notebook</Node>
            <Node key="9">Safe Haven</Node>
        </Node>
        <Node key="5">Anime
            <Node key="9">Full Metal Alchemist</Node>
            <Node key="10">Pokemon 2000: The Movie</Node>
        </Node>
    </Node>
    <Node key="12">Genre Sister</Node>
</GeneralTree>

现在,我已将问题隔离到 recFunction 中的以下几行:

    cout << "DOING NODE TO ELEMENT" << endl;
    cout << node->ToText()->Value() << endl;
    cout << "Node is of type: " << typeid(node).name() << endl;
    cout << node->ToElement()->Attribute("key") << endl;
    cout << "DONE WITH NODE TO ELEMENT" << endl;

所以我假设节点在递归函数中的某个点变为空。问题是我一遍又一遍地查看这个,我似乎无法弄清楚为什么。适当的检查应防止节点变为空。

这是我收到的输出(包括打印语句,以便您查看发生的位置)。

Right BEFORE recursive activates
First child element is null
After recursiveness done
DOING NODE TO ELEMENT
Genres
Node is of type: P9TiXmlNode

提前致谢!

编辑:这是当我运行 gdb 并在处使用断点时发生的情况

    cout << node->ToText()->Value() << endl;

和 cout ToElement()->Attribute("key")

Right BEFORE recursive activates
First child element is null
After recursiveness done
DOING NODE TO ELEMENT

Breakpoint 1, GeneralTree<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::recFunction (this=0x100300040, node=0x1003005c0)
    at ./GeneralTree.h:70
70              cout << node->ToText()->Value() << endl;
(gdb) c
Continuing.
Genres
Node is of type: P9TiXmlNode

Breakpoint 2, GeneralTree<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::recFunction (this=0x100300040, node=0x1003005c0)
    at ./GeneralTree.h:72
72              cout << node->ToElement()->Attribute("key") << endl;
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
TiXmlAttributeSet::Find (this=0x60, name=0x100018ede "key") at tinyxml.cpp:1527
1527        for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )

【问题讨论】:

  • 尝试使用调试器单步调试代码。
  • @IvanRubinson 我试过了。问题是,我的调试器不工作 :( 计划在我解决这个问题后立即解决。
  • 没有调试器就无法进行编程。先解决这个问题。
  • @IvanRubinson 好的,我已经修好了。我已经通过它,它给了我我已经拥有的相同信息。我已经用它编辑了我的原始回复。
  • 经过多少次迭代后,您会出现段错误?那么你的局部变量的值是多少呢?

标签: c++ recursion tree tinyxml


【解决方案1】:

有很多事情,但它们都归结为同一个概念错误。

XML 节点包括文本、空格和属性,而不仅仅是元素。

所以如果你打算递归所有元素,这是错误的:

 return recFunction(node->FirstChild());

应该是这样的:

 return recFunction(node->FirstChildElement());

同样,在您要求NextSibling 的地方,您可能需要NextSiblingElement

例如:

int key2 = stoi(node->NextSibling()->ToElement()->Attribute("key"));

如果NextSibling 返回一个文本节点,那么ToElement 将返回null。

查看SEGV信息:

TiXmlAttributeSet::Find (this=0x60, name=0x100018ede "key") at tinyxml.cpp:1527

这显示了 0x60 的 this 指针值,这不太可能是有效的。获得这样一个指针的最有可能的方法是在空指针的类型转换中进行未经检查的指针调整。 IE。您在某个时候使用了空指针,并且您的代码或库代码已将其转换为相关类型。

在这种情况下,由于node-&gt;ToText() 成功,那么node-&gt;ToElement() 必然会返回null,因为节点要么是文本节点,要么是元素节点。所以ToElement的返回值为null,调用Attribute是错误的。

【讨论】:

  • 感谢您的帮助!
猜你喜欢
  • 2020-05-28
  • 2021-02-25
  • 1970-01-01
  • 2018-09-10
  • 2020-03-22
  • 1970-01-01
  • 1970-01-01
  • 2017-11-12
相关资源
最近更新 更多