我试图弄清楚下面的函数是如何工作的,并且大多数情况下它运行良好(所以我想也学习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 l
,unsigned char *buf
,int begin
,int 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;
}
答案 0 :(得分:1)
这是我的尝试(我不确定是否所有必要的内容,
对于它的价值,示例程序仅需要ctype.h
和assert.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
的单独,可修改的数组,其长度和初始内容与指定的字符串文字匹配。