提问人:Davood 提问时间:9/18/2023 最后编辑:Davood 更新时间:9/19/2023 访问量:99
使用 strtok 多次拆分一个字符串会导致意外行为
using strtok to split one string more than once leads to an unexpected behavior
问:
我遇到了一个问题,我需要有人来解释发生了什么。
我正在解析一个字符串,我想将其解析为,然后拆分每个.a=1&b=2&c=3
["a=1","b=2","c=3"]
x=y
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void f2(char *src)
{
char *dest = (char *) calloc(strlen(src)+1,sizeof(char));
strcpy(dest,src); // I copy src to dest to guard src from being messed up with strtok
// when I comment out the below line, src address doesn't change
// but why is it changing the src address? I have copied the src to dest!
char *token = strtok(dest, "=");
printf("dest addr: %p token addr: %p \n",dest,token);
}
void f1(char *src)
{
char *token = strtok(src, "&");
while (token)
{
printf("src addr: %p ", token);
f2(token);
token = strtok(NULL, "&");
}
}
我运行的代码如下:
TEST(CopyPointer, CopyStrTok)
{
char str[]="a=1&b=2&c=3";
f1(str);
}
结果如下:
src addr: 0x7ffd4a00ec0c dest addr: 0x558a755d3350 token addr: 0x558a755d3350 // it's fine
src addr: 0x558a755d3352 dest addr: 0x558a755d3370 token addr: 0x558a755d3370
// ^ ^
// now src addr is changed and it's pointing to the second character of dest
我无法解释为什么 在我将 复制到另一个名为 ?src
f2
src
dest
校正:
正如其中一个答案中提到的,地址没有改变,只是令牌地址改变了!src
答:
0赞
0___________
9/18/2023
#1
src
没有更改,并且您会看到更改,因为您不仅打印(但在您的格式中,字符串是 src 而不是令牌)src
token
更正版本
void f1(char *src)
{
char *token = strtok(src, "&");
while (token)
{
printf("src addr: %p token addr: %p ", (void *)src, (void*)token);
f2(token);
token = strtok(NULL, "&");
}
}
3赞
dbush
9/18/2023
#2
该函数使用静态内部数据来跟踪它的位置。strtok
因此,当您调用 in 时,它与 in 该函数相关联(这与在测试函数中相同),但是当您再次调用它时,它与 with 作为第一个参数相关联,它现在与 in 相关联。然后,当您再次调用 with 作为第一个参数时,它使用指向其成员的内部指针,该成员不再在作用域内。这会触发未定义的行为。strtok
f1
src
str
f2
dest
dest
f2
strtok
f1
NULL
dest
如果要使用多个级别的 ,则应改用 允许用户传入附加参数来存储其状态。strtok
strtok_r
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void f2(char *src)
{
char *p = NULL;
char *token = strtok_r(src, "=", &p);
printf("token a=%s\n", token);
token = strtok_r(NULL, "=", &p);
printf("token b=%s\n", token);
}
void f1(char *src)
{
char *p = NULL;
char *token = strtok_r(src, "&", &p);
while (token)
{
f2(token);
token = strtok_r(NULL, "&", &p);
}
}
int main()
{
char str[] = "a=1&b=2&c=3";
f1(str);
return 0;
}
输出:
token a=a
token b=1
token a=b
token b=2
token a=c
token b=3
评论
1赞
Davood
9/18/2023
很好的解释,现在我明白了,第二个 strtok(NULL,“&”) 仍然指的是 f2 中的 dest。
1赞
Fe2O3
9/18/2023
#3
为什么要让它变得复杂?目标是提取字符串对:
int main( void ) {
char str[] = "a=1&b=2&c=3";
char *p1, *p2;
for( p1 = str; ( p1 = strtok( p1, "&=") ) != NULL; p1 = NULL ) {
p2 = strtok( NULL, "&=" );
printf( "%s ... %s\n", p1, p2 );
}
return 0;
}
输出:
a ... 1
b ... 2
c ... 3
下一个:在这种情况下,C 如何管理内存?
评论
char *dest = calloc(strlen(src) + 1,sizeof(char));
strtok(dest, "=");
src
token = strtok(NULL, "&");
dest
strtok()
strtok_r()
"&="
strdup