strtok:复制的字符指针的地址与源字符指针相同

问题描述 投票:0回答:3

我遇到了问题,我需要有人解释发生了什么。

我正在解析像

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
的变量?

c pointers strtok
3个回答
1
投票

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

1
投票

为什么要把事情搞复杂呢?目标是提取字符串:

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

0
投票

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, "&");
    }
} 
© www.soinside.com 2019 - 2024. All rights reserved.