* str = 0的问题导致细分错误

时间:2020-09-21 19:41:20

标签: c

我试图弄清楚下面的函数是如何工作的,并且大多数情况下它运行良好(所以我想也学习C的工作方式)。但是,我遇到了一个问题。在具有

的行上

*q = 0, chr = p, ...

如果我在单独的示例代码中执行此操作,则会遇到分段错误。我知道以下功能来自该程序,并且它使用此功能。我想知道我缺少什么。 This answer似乎暗示我正在尝试编辑一些我无法编​​辑的内容,以下功能有什么区别?

static void parse_chr(struct hk_sdict *d, char *s) // io.c 282, *d is hk_map -> d
{
    char *chr, *p, *q;
    int64_t len;
    int has_digit, prelen;
    prelen = strncmp(s, "#chromsize:", 11) == 0? 11 : 12;
    for (p = s + prelen; isspace(*p) && *p != 0; ++p) {}
    assert(*p);
    for (q = p; *q != 0 && !isspace(*q); ++q) {}
    assert(*q);
    *q = 0, chr = p, p = q + 1;
    // ... there is more to this function, but didn't seem relevant to the question, it manipulates the resulting p and chr from here via other functions in the program
}

上述功能将要查看的文本示例是文本文件中的行,例如:

#chromsize: chr1    249250621
#chromsize: chr10   135534747
...

s上的更新:

s在先前的数据结构中定义如下:

typedef struct __kstring_t {
    size_t l, m;
    char *s;
} kstring_t

后来,kstring_t的初始化如下:

kstring_t str = {0,0,0};

然后,在给定size_t值m(存储在相同结构str中)的情况下,

str->s = (char*)realloc(str->s, str->m);

然后使用(鉴于size_t lunsigned char *bufint beginint i)对此进行更新:

memcpy(str->s + str->l, ks->buf + ks->begin, i - ks->begin);

这是对s的处理,然后将其传递给上述函数。

这是我的尝试(我不确定所有包含的内容是否都是必需的,只是想复制原始脚本可用的软件包)(这给了我一个分段错误(内核已转储)):

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <zlib.h>

int main ()
{
    char *s = "#chromsize: chr1 249250621";
    char *p, *q, *chr;
    for (p = s + 11; isspace(*p) && *p != 0; ++p) {}
    assert(*p);
    for (q = p; *p != 0 && !isspace(*p); ++p) {}
    assert(*q);
    *q = 0;
    chr = p, p = q + 1;
}

1 个答案:

答案 0 :(得分:1)

这是我的尝试(我不确定是否所有必要的内容,

对于它的价值,示例程序仅需要ctype.hassert.h

只想复制原始版本可用的软件包 脚本)

您听起来像Python程序员。 #include指令不会使“包”对任何东西都可用。包不是C概念。一般而言,标头提供函数的声明,并偶尔提供假定在程序外部定义的变量,并且通常定义一个或多个预处理器宏。有必要在调用函数之前先声明它们,并在访问它们之前先声明变量,但这不是足够的。功能实现和/或变量定义也必须链接到程序。对于C标准库的成员来说,这通常是自动的,但对于其他外部函数则不是自动的。

(这给了我一个分段错误(核心已转储)):

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <zlib.h>

int main ()
{

这是主要问题:

    char *s = "#chromsize: chr1 249250621";

它声明s为指针,最初指向字符串文字中的第一个字符。字符串文字不能修改。尝试这样做会产生不确定的行为,其中段错误是非常合理的表现。

Blockquote

    char *p, *q, *chr;

请注意,这里...

    for (p = s + 11; isspace(*p) && *p != 0; ++p) {}

... p,也是一个指针,最初设置为指向字符s所指向的字符之后的字符11,该字符也位于文字中(并且指针加法将产生如果UB产生的结果指向字面量末尾超过一个字符,那么也是如此。

    assert(*p);

类似地,这里...

    for (q = p; *p != 0 && !isspace(*p); ++p) {}

... q设置为p(指向字符串文字)。

    assert(*q);

因此,当您这样做时:

    *q = 0;

...您正在尝试修改文字。哎呀。这与该赋值是在单独的语句表达式中(如上所述)还是在较大的表达式(如

)中执行无关
*q = 0, chr = p, ...

您可以通过确保未将字符串文字分配给类型为char *的指针来争取编译器的帮助来检测此类问题。而是使用类型const char *。 C的发展历史令人遗憾的是,C并不需要它。

您可以通过以下方式声明s来修复示例程序:

    char s[] = "#chromsize: chr1 249250621";

这为您提供了char的单独,可修改的数组,其长度和初始内容与指定的字符串文字匹配。