我遇到了问题,我需要有人解释发生了什么。
我正在解析像
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),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
的变量?
strtok
函数使用静态内部数据来跟踪它的位置。
因此,当您在
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
为什么要把事情搞复杂呢?目标是提取对字符串:
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
src
没有改变,您会看到变化,因为您不打印 src
仅 token
(但在您的格式字符串中是 src 而不是令牌)
更正版本
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, "&");
}
}