理解 strtok 返回的指针
understanding the pointer returned by strtok
我有这段代码,我在其中标记了一个字符串并搜索了一个值。
char string[]="Name=Marcus&greeting=goodmorning";
char* Name=parsePostData("Name",string);
char* parsePostData(char s[],char t[])
{
char *pch;
char *pp="Marcus";
char tCpy[512];//Make a copy. Otherwise, strtok works on the char pointer, and original char array gets modified/ corrupted.
strcpy(tCpy,t);
pch = strtok (tCpy,"=&");
while (pch != NULL)
{
if(strcmp(pch,s)==0) {
pch= strtok (NULL, "&");
//Case 1. what I need. but it is causing issues
//after I write to flash, and restart the board.
return pch;
//Case 2. Forced test case. works perfect.
//return pp;
}else{
pch = strtok (NULL, "=&");
}
}
}
函数内部的两种情况有什么区别?
what is the difference between the two cases inside the function?
案例一
正如几个人现在告诉你的那样,序列
pch = strtok (tCpy,"=&");
/* ... */
pch= strtok (NULL, "&");
导致 pch
成为局部数组 tCpy
的指针(或 NULL,如果原始字符串不包含“=”或“&”)。因为 tCpy
是一个 local 数组,它在函数结束时超出范围,此时任何指向它的指针都不再有效。实际上,它占用的内存可能会被下一个调用的函数重用。
案例二
密码
char *pp="Marcus";
初始化 pp
以指向一个静态的匿名字符数组,其内容是空终止字符串 "Marcus"
。因为该数组具有静态存储持续时间,所以指向它的指针在函数退出后仍然有效。
您有三个主要选项来解决此问题:
- 调用方为字符串副本提供函数预分配存储空间。这可能是一个工作数组(不一定是动态分配的),或者它可以采取让函数使用字符串的形式,caller 负责在必要时制作副本。
- 该函数为副本动态分配存储空间。可以采用的方法有很多,但
strdup()
函数是一种快速简便的一步分配和复制方法。
- 您可以将数组
tCpy
设为静态。然后指向它的指针在函数 return 之后仍然有效,但是 space 将在每次调用该函数时重复使用,可能会更改指针指向的文本。
注意: 将内存分配给调用者 return 的函数的任何变化都会让调用者负责 释放 该内存不再使用时。这样做需要一个指向分配块的 start 的指针,而不是指向中间某个随机位置的指针,因此您需要传回两个指针才能使其工作(一个通过参数).
总而言之,我认为您选择选项 1 的变体是明智的。如果是我,我会让函数使用传递给它的字符串。
更新:
此外,在情况 2 中,程序映像包含您的指针指向的数据。假设它总是加载在相同的地址,保存和恢复指针值而不是它指向的值可能只对那个程序有效,因为你通过加载程序图像来重新初始化指向内存。如果将字符串复制到工作数组中,则同样不适用,因为即使数组具有静态持续时间,它也不会使用要恢复的数据进行初始化。
我有这段代码,我在其中标记了一个字符串并搜索了一个值。
char string[]="Name=Marcus&greeting=goodmorning";
char* Name=parsePostData("Name",string);
char* parsePostData(char s[],char t[])
{
char *pch;
char *pp="Marcus";
char tCpy[512];//Make a copy. Otherwise, strtok works on the char pointer, and original char array gets modified/ corrupted.
strcpy(tCpy,t);
pch = strtok (tCpy,"=&");
while (pch != NULL)
{
if(strcmp(pch,s)==0) {
pch= strtok (NULL, "&");
//Case 1. what I need. but it is causing issues
//after I write to flash, and restart the board.
return pch;
//Case 2. Forced test case. works perfect.
//return pp;
}else{
pch = strtok (NULL, "=&");
}
}
}
函数内部的两种情况有什么区别?
what is the difference between the two cases inside the function?
案例一
正如几个人现在告诉你的那样,序列
pch = strtok (tCpy,"=&");
/* ... */
pch= strtok (NULL, "&");
导致 pch
成为局部数组 tCpy
的指针(或 NULL,如果原始字符串不包含“=”或“&”)。因为 tCpy
是一个 local 数组,它在函数结束时超出范围,此时任何指向它的指针都不再有效。实际上,它占用的内存可能会被下一个调用的函数重用。
案例二
密码
char *pp="Marcus";
初始化 pp
以指向一个静态的匿名字符数组,其内容是空终止字符串 "Marcus"
。因为该数组具有静态存储持续时间,所以指向它的指针在函数退出后仍然有效。
您有三个主要选项来解决此问题:
- 调用方为字符串副本提供函数预分配存储空间。这可能是一个工作数组(不一定是动态分配的),或者它可以采取让函数使用字符串的形式,caller 负责在必要时制作副本。
- 该函数为副本动态分配存储空间。可以采用的方法有很多,但
strdup()
函数是一种快速简便的一步分配和复制方法。 - 您可以将数组
tCpy
设为静态。然后指向它的指针在函数 return 之后仍然有效,但是 space 将在每次调用该函数时重复使用,可能会更改指针指向的文本。
注意: 将内存分配给调用者 return 的函数的任何变化都会让调用者负责 释放 该内存不再使用时。这样做需要一个指向分配块的 start 的指针,而不是指向中间某个随机位置的指针,因此您需要传回两个指针才能使其工作(一个通过参数).
总而言之,我认为您选择选项 1 的变体是明智的。如果是我,我会让函数使用传递给它的字符串。
更新: 此外,在情况 2 中,程序映像包含您的指针指向的数据。假设它总是加载在相同的地址,保存和恢复指针值而不是它指向的值可能只对那个程序有效,因为你通过加载程序图像来重新初始化指向内存。如果将字符串复制到工作数组中,则同样不适用,因为即使数组具有静态持续时间,它也不会使用要恢复的数据进行初始化。