2017-05-15 35 views
-1

下面的函数tokenize用来设置* str的大小为0,如果sprt不存在于str内 - 如果sprt指向“|”并以“d AO d”,块[1]假设STR指向一个NULL指针和n被设置为0:未定义的行为:strtok

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

不要调用'free(chunk [1])';你应该只用'malloc'家族'free'分配东西 –

+0

这与你遇到的任何问题没有任何关系,但我总是喜欢指出'strdup()'是一个比'malloc更好的选择()'/'strcpy()'组合。更少的错误和更可读性。 –

回答

2

第一strtok调用返回一个指向原始字符串"D AO D",由于没有"|"定界符在此字符串:

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

然后while循环条件的推移,因为chunk[1]是一个非空指针:

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

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

+0

我没有发布strtok在分隔符错误的情况下返回原始字符串。谢谢。 – Kais

+1

@Kais:如果字符串中没有分隔符,那么字符串就是唯一的标记。 –