【问题标题】:C: Segmentation fault, why and how to fixC:分段错误,为什么以及如何修复
【发布时间】:2019-12-08 16:58:14
【问题描述】:


我目前正在学习如何编程,我很确定我的代码充满了错误。
我在执行这段代码时遇到了分段错误,我不知道为什么。

#include <stdio.h>
#include <libxml/parser.h>
#include <string.h>
#include <stdlib.h>


typedef struct
{
        int ac; /**< The player armor class. */
        char *class; /**< The player class. */
        char *cname; /**< The player character name. */
        int cp; /**< The player money (copper pieces, 100 CP = 1 GP). */
        int gp; /**< The player money (gold pieces). */
        int hp; /**< The player hit points. */
        char *name; /**< The player name. */
        int sp; /**< The player money (silver pieces, 10 SP = 1 GP). */
} player_t;

void parsePlayer(xmlDocPtr doc, xmlNodePtr node){
    int i = 1;
    player_t players[3];
    xmlNodePtr cur;

    node = node->xmlChildrenNode;

    while(node!=NULL){
        if (!xmlStrcmp(node->name, (const xmlChar *) "player"))
        {
            players[i].name = (char *) xmlGetProp(node, (const xmlChar *)"name");
            printf("player %d name: %s\n", i, players[i].name);
            cur = node->xmlChildrenNode;
            players[i].ac = strtol((char *) xmlNodeListGetString(doc, cur->xmlChildrenNode, 1),NULL,10);
            i++;
        }

        node = node->next;
    }
}

void parsePlayers(xmlDocPtr doc){
    xmlNodePtr node;

    node = xmlDocGetRootElement(doc);

    node = node->xmlChildrenNode; 

    while(node!=NULL){
        if (!xmlStrcmp(node->name, (const xmlChar *) "players")){
            parsePlayer(doc, node);
        }
        node = node->next;
    }
}

int main(int argc, char const *argv[]) {

    xmlDocPtr doc = xmlParseFile(argv[1]);

    if (doc != NULL) printf("DEBUG: File parsed.\n");   
    else { 
        fprintf(stderr,"Unable to parse the document \n");
        return 1;
    }

    parsePlayers(doc);
    return 0;
}

代码显示如下:

DEBUG: File parsed.
player 1 name: Camille /* correct */
Segmentation Fault

我试过寻找答案,但似乎我不够先进,无法理解它们:/。
这是针对学校的一个项目(我必须填充几个 player_t 结构)。
我不认为错误来自 XML,因此无需在此处发布。
我已经被这个错误困扰了几天了,我很想知道如何纠正它。
感谢阅读:)。

编辑:感谢您的回答,gdb 说:

Program received signal SIGSEGV, Segmentation fault.
__GI_____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group=<optimized out>, 
    loc=0x7ffff7a0f560 <_nl_global_locale>) at ../stdlib/strtol_l.c:292
292 ../stdlib/strtol_l.c: no such file or directory. 

我不知道这是什么意思:(。

编辑2:好的,错误确实来自xml,这里是:

<ddg name="The frozen cave">
        <date>
                <day>01</day>
                <month>09</month>
                <year>2019</year>
        </date>
        <dmname>Pierre</dmname>
        <players>
                <player name="Camille">
                        <ac>5</ac>
                        <class>Thief</class>
                        <cname>Camigolas</cname>
                        <hp>4</hp>
                        <money>
                                <cp>10</cp>
                                <gp>10</gp>
                                <sp>10</sp>
                        </money>
                </player>
                <player name="Jean">
                        <ac>4</ac>
                        <class>Fighter</class>
                        <cname>Jeragorn</cname>
                        <hp>8</hp>
                        <money>
                                <cp>3</cp>
                                <gp>1</gp>
                                <sp>2</sp>
                        </money>
                </player>
                <player name="Paul">
                        <ac>5</ac>
                        <class>Cleric</class>
                        <cname>Paumli</cname>
                        <hp>6</hp>
                        <money>
                                <cp>9</cp>
                                <gp>5</gp>
                                <sp>9</sp>
                        </money>
                </player>
        </players>
</ddg>

我尝试了几件事,最终发现播放器的 xmlChildrenNode 是文本。
我想我只需要循环直到找到我想要的元素,但有谁知道它为什么返回文本? (我只是 printf cur->name 来发现这一点)。
谢谢大家的回答:)!

【问题讨论】:

  • 使用调试信息 (-g) 编译您的代码并在 gdb 下运行它:gdb --args ./myprog
  • 在调用 strtol 之前检查 xmlNodeListGetString 给出的内容,因为至少一旦你得到一个空指针而不是一个字符串(在 xml 中丢失,或者我猜不是在哪里寻找)
  • 我注意到您正在设置cur = node-&gt;xmlChildrenNode,但随后在对xmlNodeListGetString 的调用中再次使用cur-&gt;xmlChildrenNode。你是故意的吗?
  • 在post中包含一个xml文件的例子会很好。
  • @schtever 是的,我想这样做,所以我往下走 2 层并使用“xmlNodeListGetString”返回 xmlChar *“5”。

标签: c libxml2


【解决方案1】:

nptr=0x0 可能意味着strtol(或更确切地说是由strtol 调用的函数)是在参数nptr 设置为0x0 的情况下调用的。参数nptr 最像预期的指向一个有效字符串,但没有。

这可能意味着xmlNodeListGetString() 返回零或NULL,具体取决于您喜欢如何调用该值。

解析外部文件时,您应该始终对文件内容进行错误检查。

我猜cur-&gt;xmlChildrenNode 没有您期望的价值,但如果没有更多信息很难说。

顺便说一句,c 是具有从零开始的数组的语言之一,因此您应该拥有int i = 0。 (基于 1 的数组是邪恶的。)不要通过在 players[0] 处具有虚拟元素来模拟基于 1 的数组来成为异端。

【讨论】:

  • 所以在我的代码中 player[0] 存在吗?哎哟那确实很丑:(
【解决方案2】:

我尝试了几件事,最终发现播放器的 xmlChildrenNode 是文本。我想我只需要循环直到找到我想要的元素,但有人知道它为什么返回文本

XML 文件中元素之间的所有空格都很重要。 节点将有 11 个子节点:

  • 一个文本节点,之后的换行符和之前的空格
  • 元素节点,即(将有一个文本节点子节点,即ac值)
  • 一个文本节点,之后的换行符和之前的空格
  • 元素节点,即
  • 等等……

因此,您在 下看到的第一个“文本”子项是 之前出现的换行符和空格。

您可能希望将 XML_PARSE_NOBLANKS 传递给 xmlParseFile,它会告诉解析器像这样跳过“中间”空白。然后 将有 子节点,然后是 子节点,等等,中间没有文本节点。

【讨论】:

    猜你喜欢
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    相关资源
    最近更新 更多