C语言中使用strtok进行字符串解析

4

我有一小段源代码,用于测试解析类似于变量string的字符串,我需要在其他项目中使用它。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main (void)
{
    char string[] = "C-AC-2C-3C-BOB";
    char* s;
    char* hand[3];
    char* usr;


    s = (char*) calloc(1, sizeof(char));
    hand[1] = (char*) calloc(3, sizeof(char));
    hand[2] = (char*) calloc(3, sizeof(char));
    hand[3] = (char*) calloc(3, sizeof(char));
    usr = (char*) calloc(21, sizeof(char));

    s = strtok (string,"-");
    hand[1] = strtok (NULL, "-");
    hand[2] = strtok (NULL, "-");
    hand[3] = strtok (NULL, "-");
    usr = strtok (NULL, "\0");

    printf("%s:%s:%s:%s:%s\n", s, hand[1], hand[2], hand[3], usr);

    return 0;
}

问题在于我得到的这些3C:AC:2C:3C:BOB,而不是C:AC:2C:3C:BOB,这是printf的结果。

-------编辑-----

没有内存泄漏的代码。问题仍然存在。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main (void)
{
    char string[] = "C-AC-2C-3C-BOB";
    char* s;
    char* hand[3];
    char* usr;

    s = strtok (string,"-");
    hand[1] = strtok (NULL, "-");
    hand[2] = strtok (NULL, "-");
    hand[3] = strtok (NULL, "-");
    usr = strtok (NULL, "\0");

    printf("%s:%s:%s:%s:%s\n", s, hand[1], hand[2], hand[3], usr);

    return 0;
}

3
你的程序存在内存泄漏问题。首先你分配了一些内存并将其分配给一组指针,然后你使用strtok函数的结果覆盖了那些指针。 - Some programmer dude
好的,使用calloc编辑分配的整个部分并不能解决主要问题。 - Arrigo Pierotti
@ArrigoPierotti 删除所有 calloc() 行,然后重新编译和运行。 - Grijesh Chauhan
@GrijeshChauhan的代码已经被编辑,但问题仍然存在。 - Arrigo Pierotti
1
在C语言中,数组是以0为基础索引的。 - alk
5个回答

4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main (void)
{
    char string[] = "C-AC-2C-3C-BOB";
    char* s;
    char* hand[3];
    char* usr;

    s = strtok (string,"-");
    hand[0] = strtok (NULL, "-");
    hand[1] = strtok (NULL, "-");
    hand[2] = strtok (NULL, "-");
    usr = strtok (NULL, "\0");

    printf("%s:%s:%s:%s:%s\n", s, hand[0], hand[1], hand[2], usr);

    return 0;
}

您不需要使用calloc来分配指针的内存,因为strtok()将返回一个有效的内存地址(实际上,strtok()会修改字符串并用空字符替换分隔符)。另一个问题是数组的索引:在C语言中,索引从0开始。 hand数组的第一个元素是hand[0],最后一个元素是hand[2]


4
您声明了一个包含三个元素的数组hand,然后使用索引13进行索引。但是在C语言中,数组的索引从0size-1(例如,在您的情况下为2)。
因此,您会读/写超出数组边界,导致未定义的行为。
请将数组的索引更改为02,它应该可以正常工作。

1
哦糟糕 >> 之前没注意到这个愚蠢的错误 >> 现在程序已经正常工作了,谢谢 - Arrigo Pierotti

4

在您的代码中,存在超出索引的问题,导致运行时出现未定义行为:

hand[3] = strtok (NULL, "-"); 
     ^

printf("%s:%s:%s:%s:%s\n", s, hand[1], hand[2], hand[3], usr);
                                                     ^
                                                 wrong index value   

请记住,根据声明 char* hand[3]; 数组中的索引值从0开始,可以是0到2的值。


哦,糟糕 >> 我没有注意到这个愚蠢的错误 >> 程序现在已经正确运行了,谢谢。 - Arrigo Pierotti
@ArrigoPierotti 还有一件事是,strtok() 修改了输入字符串,并用 \0 替换了所有分隔符。 - Grijesh Chauhan
@ArrigoPierotti 请查看这个答案。我的意思是,如果你准备修改你的字符串,那么就用冒号 : 替换原始字符串中的破折号 - - Grijesh Chauhan

1
这是你的程序堆栈:

+-----------------------+
|       ...
|
|0x***00 hand[0]
|
|
|           
|0x***04 hand[1]       
|
|
|     
|0x***08 hand[2]           
|                  
|
|
|0x***0C hand[3]    
|                       <---hander[1] pointer this address    
|    
|______  hand[3] end here 

因此,手[3]使用地址来覆盖手[1],这就是3C的含义。


0
首先,你应该注释掉这些行以避免内存泄漏:
s = (char*) calloc(1, sizeof(char));
hand[1] = (char*) calloc(3, sizeof(char));
hand[2] = (char*) calloc(3, sizeof(char));
hand[3] = (char*) calloc(3, sizeof(char));
usr = (char*) calloc(21, sizeof(char));

然后,在修改代码后,我在Windows和Linux上构建并运行结果,都没有得到您意外的打印结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接