【问题标题】:Why is strtok causing a segmentation fault?为什么 strtok 会导致分段错误?
【发布时间】:2010-03-05 09:36:19
【问题描述】:

为什么下面的代码会给出 Seg.最后一行出错了?

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

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

【问题讨论】:

  • ReadName() 是做什么的?它是如何分配返回值的?

标签: c string segmentation-fault


【解决方案1】:

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

也许 ReadName() 返回一个指向只读字符数组的指针。你能告诉我们你的 ReadName() 函数吗?

如果这是 seg-faullt 的原因,您可以在使用 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()的返回值是如何分配的问题,其他人在他们的回答中已经解决了。

    【讨论】:

      【解决方案3】:

      如果不知道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.
      

      【讨论】:

        【解决方案4】:

        这可能是因为ReadName() 返回字符串。因此,赋值使m const char* 并且因此,您不能 更改它的任何值(修改字符串)。所以,当 'strtok' 试图修改 'm' 时,Segmentation Fault 就出现了

        补救措施:

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

        char *m = strdup(ReadName());

        【讨论】:

          【解决方案5】:

          以下代码取自 BSD 许可的 C 字符串处理库,称为 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 */
          

          【讨论】:

            猜你喜欢
            • 2020-04-15
            • 1970-01-01
            • 2021-04-08
            • 2021-07-18
            • 2020-10-28
            • 1970-01-01
            • 2017-08-18
            • 1970-01-01
            • 2013-10-18
            相关资源
            最近更新 更多