strtok给出分段错误

时间:2010-03-05 09:36:20

标签: c string segmentation-fault

为什么以下代码会给Seg。最后一行出错了?

char* m=ReadName();
printf("\nRead String %s\n",m); // Writes OK
char* token;
token=strtok(m,'-');

如上所述,读取字符串打印没有问题,但为什么不能拆分为令牌?

5 个答案:

答案 0 :(得分:17)

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

也许ReadName()返回一个指向只读char数组的指针。您可以向我们展示您的ReadName()函数。

如果是seg-faullt的原因,您可以使用strdup函数将char数组传递给strtok之前创建一个char数组的副本:

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

答案 1 :(得分:2)

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

char *strtok(char *str, const char *delim);

'-'的ASCII码是0x2D,因此将其作为strtok()的第二个参数传递将导致strtok()取消引用地址0x0000002D,这将导致段错误或访问冲突最现代的操作系统。要解决此问题,请使用字符串文字而不是字符文字:token=strtok(m,"-");

还有一个问题是如何分配ReadName()的返回值,其他人在答案中已经解决了这个问题。

答案 2 :(得分: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.

答案 3 :(得分:0)

可能是因为ReadName()返回字符串。因此,赋值使m const char *,因此,不能更改其任何值(修改字符串)。因此,当'strtok'尝试修改'm'时, Segmentation Fault 就在那里

处理:

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

OR

char *m = strdup(ReadName());

答案 4 :(得分:0)

以下代码取自C的BSD许可字符串处理库,名为zString

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;
}

This post很好地解释了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 */