【问题标题】:Segmentation fault in parsing code解析代码中的分段错误
【发布时间】:2015-07-30 18:38:21
【问题描述】:

我有这段代码可以提取两个指定字符串之间的字符串,特别是<title></title>。但是当我运行程序时,我得到Segmentation Fault: 11 任何解决方案?

int main(){

        struct stat st;
        stat("test.txt", &st);
        int size = st.st_size;
        printf("%d\n", size);
        FILE *f = fopen("test.txt", "rb");

        char *bytes = (char*)malloc(size);        
        fread(bytes,size,1,f);
        fclose(f);
        parser(bytes);
        return 0;
}

void parser(char *bytes){
        struct stat st;
        stat(bytes, &st);
        int size = st.st_size;
        char *output = (char*)malloc(size);
        char *ptr = strstr(bytes, "<title>");
        char *ptr2 = strstr(ptr, "</title>");
        if(ptr2){
            strncpy(output, ptr+7, (ptr2 - (ptr+7)));
            puts(output);
            free(output);
            parser(ptr2);
        }
        free(bytes);
        free(output);

}

【问题讨论】:

  • 您正在测试 'yeah.txt' 的大小,然后打开 'test.txt'?
  • 因为你stat文件的内容而不是parser中的文件名?您的 char 缓冲区 bytesoutput 不是以 null 结尾的,这是 &lt;string.h&gt; 中的函数所必需的,例如strstr.
  • @narb 抱歉,它应该是 'test.txt' 而不是 'yeah.txt'
  • @MiguelLorenzoPanagsagan:专业提示:使用变量作为文件名,而不是在每次出现时都对其进行硬编码,因此您只需将其维护在一个地方。
  • 只是一个简单的txt文件。 Hello &lt;title&gt;Hello&lt;/title&gt; &lt;title&gt;Hi&lt;/title&gt; hello &lt;title&gt;hello&lt;/title&gt;

标签: c parsing segmentation-fault


【解决方案1】:

这里有很多问题。

不分先后:

  • 你正在双重释放output(在你找到一个字符串的情况下)。这极有可能引发段错误,尽管不一定在第二次调用free 时发生。即使malloc 不是从malloc 返回的地址(在解析的递归调用中),您也会释放bytes。这也会导致问题,而且是糟糕的设计:函数通常不应释放作为参数传递给它们的字符串。

  • 在解析器中,您在文件内容上调用stat,而不是在文件名上。这通常会失败,size 将毫无意义。这尤其令人震惊,因为您实际上并不需要大小。

  • 您可能不想使用strncpystrncpy 不会以空值终止副本,除非在原始文件中找到 NUL。所以你最终会得到一个未终止的副本,这可能会造成各种破坏。

    相反,只需使用memcpy(它也不会以空值终止,但至少不会让您误以为它可能会这样)并自己添加 NUL。

  • 您最初从文件中读取的字符串不是 NUL 终止的。所以strstr 将继续读取超出字符串末尾的内容。

  • parser 是递归的,而不是尾递归的。它可以很容易地编写为尾递归,并且您的 C 编译器可能能够在这种情况下应用 TCO,但按照编写的方式,它有可能构建一个大型调用堆栈。

  • parser 在对结果调用 strstr 之前不会验证第一个 strstr 是否找到了字符串。因此,当没有更多 &lt;title&gt; 可供查找时,您将调用 ptr2 = strstr(NULL, "&lt;/title&gt;");。那肯定会出现段错误。

这里有一些可能有帮助的代码:

/* Forward declare parser */
void parser(char *bytes);

int main(){
        struct stat st;
        stat("test.txt", &st);
        /* CHECK RETURN VALUE */
        int size = st.st_size;
        printf("%d\n", size);
        FILE *f = fopen("test.txt", "rb");
        /* CHANGE: need space for the NUL */
        char *bytes = malloc(size + 1);        
        size_t nread = fread(bytes,size,1,f);
        if (nread != size) { /* HANDLE ERROR */ }
        /* CHANGE: NUL terminate string */
        bytes[nread] = 0;
        fclose(f);
        parser(bytes);
        /* CHANGE: We allocated bytes, we free it */
        free(bytes);
        return 0;
}

void parser(char *bytes){
    char *ptr = strstr(bytes, "<title>");
    /* CHANGE: Make sure strstr found something */
    if (ptr) {
        /* Skip over the found string */
        ptr += 7:
        char *ptr2 = strstr(ptr, "</title>");
        if (ptr2) {
            /* Don't allocate buffer until we need it */
            /* Remember to leave space for the NUL */
            char* output = malloc(ptr2 - ptr + 1);
            memcpy(output, ptr, ptr2 - ptr);
            /* null-terminate */
            output[ptr2 - ptr] = 0;
            puts(output);
            free(output);
            parser(ptr2);
        }
    }
}

这也不是最好的代码。但它显示了一些你可以考虑的事情。

【讨论】:

  • 感谢您的代码。这真的很有帮助。不过有一个问题。运行代码时 *ptr 的值为 null。
  • 当我尝试在 main 中打印字节时,只复制了文件的第一个字符。
  • @miguel:对不起,我刚刚复制了你的代码。 fread 应该是 fread(bytes, 1, size, f)。阅读 man fread 和我编写的代码以了解原因。
  • 感谢您的帮助。我也发现了问题。它现在正在工作。
猜你喜欢
  • 2012-01-19
  • 2015-08-02
  • 1970-01-01
  • 2011-07-17
  • 1970-01-01
  • 2013-04-12
  • 1970-01-01
  • 2021-06-26
相关资源
最近更新 更多