为什么strtok会导致分段错误?

4
为什么下面的代码在最后一行会导致段错误?
char* m=ReadName();
printf("\nRead String %s\n",m); // Writes OK
char* token;
token=strtok(m,'-');

正如所说,读取字符串没有问题,但为什么无法分割成标记?

ReadName() 函数是做什么的?它如何分配返回值? - Pointy
5个回答

18

strtok 修改了它的第一个参数,因此该参数应该是可修改的。

也许 ReadName() 返回的是指向只读 char 数组的指针。你能给我们展示一下你的 ReadName() 函数吗?

如果 那是 seg-fault 的原因,你可以使用 strdup 函数在将其传递给 strtok 之前创建 char 数组的副本,例如:

char *copy = strdup(m);
token = strtok(copy,'-');
....
....
free(copy); // free the copy once you are done using it.

2

token=strtok(m,'-');应该会生成编译器警告,因为strtok()的第二个参数是指向多个分隔符的const char *,而不是单个char分隔符:

char *strtok(char *str, const char *delim);
'-'的ASCII码为0x2D,因此将其作为strtok()的第二个参数传递将使strtok()解引用地址0x0000002D,在大多数现代操作系统上会导致段错误或访问冲突。要解决这个问题,请使用字符串文字而不是字符文字:token=strtok(m,"-"); 还有一个问题是如何分配ReadName()的返回值,其他人在他们的答案中已经解决了这个问题。

0

下面的代码取自一个名为zString的C语言字符串处理库,使用BSD许可证。

https://github.com/fnoyanisi/zString

从函数的实现可以看出,strtok()(或在这种情况下是zstring_strtok())依赖于一个static *char来保留分隔符的最后位置,并实际修改原始字符串。
char *zstring_strtok(char *str, const char *delim) {
    static char *static_str=0;      /* var to store last address */
    int index=0, strlength=0;       /* integers for indexes */
    int found = 0;                  /* check if delim is found */

    /* delimiter cannot be NULL
    * if no more char left, return NULL as well
    */
    if (delim==0 || (str == 0 && static_str == 0))
        return 0;

    if (str == 0)
        str = static_str;

    /* get length of string */
    while(str[strlength])
        strlength++;

    /* find the first occurance of delim */
    for (index=0;index<strlength;index++)
        if (str[index]==delim[0]) {
            found=1;
            break;
        }

    /* if delim is not contained in str, return str */
    if (!found) {
        static_str = 0;
        return str;
    }

    /* check for consecutive delimiters
    *if first char is delim, return delim
    */
    if (str[0]==delim[0]) {
        static_str = (str + 1);
        return (char *)delim;
    }

    /* terminate the string
    * this assignmetn requires char[], so str has to
    * be char[] rather than *char
    */
    str[index] = '\0';

    /* save the rest of the string */
    if ((str + index + 1)!=0)
        static_str = (str + index + 1);
    else
        static_str = 0;

        return str;
}

这篇文章很好地解释了char s[]char *s之间的区别。因此,

char s[]="Test to pass strtok()"; /* this can be passed to strtok() */
char *m="Test to pass strtok()"; /* passing this will result in SIGSEGV */

0

不知道 m 指向什么,所以无法确定。但最有可能的原因是 m 指向只读内存。因此你可以将其打印出来,但不能对其进行写入。

strtok 对字符串进行写入操作,因此会出错,但 printf 只从中读取,所以不会出错。

试试这个

char* m=ReadName();
printf("\nRead String %s\n",m); // Writes OK
char temp = m[0];
m[0] = temp; // I'll bet you segfault here.

0

这可能是因为ReadName()返回字符串。所以,赋值使m成为const char*,因此您不能更改其任何值(修改字符串)。因此,当'strtok'尝试修改'm'时,出现分段错误

解决方法:

char *m = malloc(sizeof(char)*MAX);
strcpy(m, ReadName());

或者

char *m = strdup(ReadName());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接