未定义的行为:strtok

时间:2017-05-15 00:51:25

标签: c undefined-behavior strtok

如果sprt不存在于str中,则下面的函数tokenize旨在将* size设置为0 - 如果sprt指向“|”并且str为“D AO D”,chunk [1]应该指向一个NULL指针,n设置为0:

void
tokenize(char *str,
         const char *sprt /*separator*/,
         char **buffer,
         int *size /*tokens length*/)
{
  char *chunk[2] = {NULL, NULL};

  //store str value into chunk[0]
  chunk[0] = calloc(strlen(str)+1, sizeof(char));
  strcpy(chunk[0], str);

  if (buffer!=NULL)
  {
    int sz = 0;
    chunk[1] = strtok(str, sprt);
    while (chunk[1]!=NULL)
    {
      buffer[sz] = calloc(strlen(chunk[1])+1, sizeof(char));
      strcpy(buffer[sz], chunk[1]);
      chunk[1] = strtok(NULL, sprt);
      sz++;
    }
  }
  else
  {
    *size=0;

    //if chunk is not NULL, the iteration begins => size > 0
    chunk[1] = strtok(str, sprt);

    while (chunk[1]!=NULL)
    {
      (*size)++;
      chunk[1] = strtok(NULL, sprt);
    }

    printf("size=%i\n", *size);
  }

  //restore str value from chunk[0]
  strcpy(str, chunk[0]);

  if (chunk[0]!=NULL) free(chunk[0]);
  if (chunk[1]!=NULL) free(chunk[1]);
}

但是,在以下代码中测试函数时,会显示bug: n really needs to be 0!,这意味着strtok无法正常工作:

int main()
{
  char *test = calloc(7, sizeof(char));
  strcpy(test, "D AO D");

  int n;
  tokenize(test, "|", NULL, &n);
  if (n>0)
    printf("bug: n really needs to be 0!\n");
  else
    printf("no bug\n");
}

我真的不知道是什么导致了这个UB。我做错了什么?

1 个答案:

答案 0 :(得分:2)

第一个strtok调用返回指向原始字符串"D AO D"的指针,因为此字符串中没有"|"分隔符:

chunk[1] = strtok(str, sprt);

然后while循环条件通过,因为chunk[1]是非NULL指针:

while (chunk[1]!=NULL)
{
  (*size)++;
  chunk[1] = strtok(NULL, sprt);
}

*size在第一次迭代中递增。当遇到终止strtok字节时,下一个NULL调用返回'\0',并且由于未满足条件而终止循环。因此,*size等于1,这是预期的行为。