2017-05-15 45 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:如果字符串中沒有分隔符,那麼字符串就是唯一的標記。 –