请考虑以下使用strtok拆分字符串madddy的代码段。
char* str = (char*) malloc(sizeof("Madddy"));
strcpy(str,"Madddy");
char* tmp = strtok(str,"d");
std::cout<<tmp;
do
{
std::cout<<tmp;
tmp=strtok(NULL, "dddy");
}while(tmp!=NULL);
工作正常,输出为Ma。但是通过将strtok修改为以下内容,
tmp=strtok(NULL, "ay");
输出变为Madd。那么strtok究竟是如何运作的呢?我有这个问题,因为我希望strtok将分隔符字符串中的每个字符作为分隔符。但在某些情况下,它是这样做的,但在少数情况下,它会产生意想不到的结果。谁能帮我理解这个?
答案 0 :(得分:10)
“试图了解strtok”祝你好运!
无论如何,我们是在2011年。令人敬畏:
std::string str("abc:def");
char split_char = ':';
std::istringstream split(str);
std::vector<std::string> token;
for (std::string each; std::getline(split, each, split_char); token.push_back(each));
:d
答案 1 :(得分:3)
strtok()
。它早于多线程环境并击败(修改)源字符串。
当使用NULL
调用第一个参数时,它会继续解析最后一个字符串。这个功能很方便,但即使在白天也有点不寻常。
答案 2 :(得分:2)
实际上你的代码错了,难怪你会得到意想不到的结果:
char* str = (char*) malloc(sizeof("Madddy"));
应该是
char* str = (char*) malloc(strlen("Madddy") + 1);
答案 3 :(得分:1)
您似乎忘记了第一次(循环外)通过分隔符“d”调用strtok。
strtok工作正常。你应该有一个参考here。
对于第二个例子(strtok("ay")
):
首先,你调用strtok(str,“d”)。它将寻找第一个“d”,并分隔你的字符串。具体来说,它设置tmp =“Ma”,str =“ddy”(丢弃第一个“d”)。
然后,你打电话给strtok(str,“ay”)。它将在str中查找“a”,但由于您的字符串现在只是“ddy”,因此不会发生匹配。然后它会寻找一个“y”。所以str =“dd”和tmp =“”。
如你所见,打印“Madd”。
答案 4 :(得分:0)
我问了另一个关于functions causing security problems/bad practise functions and the c standard library的问题的启发问题。
从那里引用给我的答案:
strtok()
常见的陷阱 函数是假设解析的 字符串保持不变,而它 实际上替换了分隔符 带有'\0'
的字符。此外,
strtok()
用于制作 后来打电话给它,直到 整个字符串被标记化。一些 库实现存储strtok()
的内部状态 全局变量,可能会诱发一些 令人讨厌的惊喜,如果是strtok()
从多个线程调用 同一时间。
当您标记了问题C ++时,请使用其他内容!如果你想使用C,我建议你实现你自己的安全标记器。
答案 5 :(得分:0)
由于您将标记更改为C而不是C ++,因此我重写了您的函数以使用printf,以便您可以看到正在发生的事情。 Hoang是对的。你看到正确的输出,但我认为你在同一行打印所有内容,所以你对输出感到困惑。看看Hoang的回答,他正确地解释了发生了什么。另外,正如其他人所说,strtok会破坏输入字符串,所以你必须要小心 - 而且它不是线程安全的。但是如果你需要一个快速的脏标记器,它就可以工作。另外,我更改了代码以正确使用strlen,而不是像Anders正确指出的sizeof。
以下是您的代码修改为更像C的代码:
char* str = (char*) malloc(strlen("Madddy") + 1);
strcpy(str,"Madddy");
char* tmp = strtok(str,"d");
printf ("first token: %s\n", tmp);
do
{
tmp=strtok(NULL, "ay");
if (tmp != NULL ) {
printf ("next token: %s\n", tmp);
}
} while(tmp != NULL);