理解 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"。因为该数组具有静态存储持续时间,所以指向它的指针在函数退出后仍然有效。


您有三个主要选项来解决此问题:

  1. 调用方为字符串副本提供函数预分配存储空间。这可能是一个工作数组(不一定是动态分配的),或者它可以采取让函数使用字符串的形式,caller 负责在必要时制作副本。
  2. 该函数为副本动态分配存储空间。可以采用的方法有很多,但 strdup() 函数是一种快速简便的一步分配和复制方法。
  3. 您可以将数组 tCpy 设为静态。然后指向它的指针在函数 return 之后仍然有效,但是 space 将在每次调用该函数时重复使用,可能会更改指针指向的文本。

注意: 将内存分配给调用者 return 的函数的任何变化都会让调用者负责 释放 该内存不再使用时。这样做需要一个指向分配块的 start 的指针,而不是指向中间某个随机位置的指针,因此您需要传回两个指针才能使其工作(一个通过参数).

总而言之,我认为您选择选项 1 的变体是明智的。如果是我,我会让函数使用传递给它的字符串。

更新: 此外,在情况 2 中,程序映像包含您的指针指向的数据。假设它总是加载在相同的地址,保存和恢复指针值而不是它指向的值可能只对那个程序有效,因为你通过加载程序图像来重新初始化指向内存。如果将字符串复制到工作数组中,则同样不适用,因为即使数组具有静态持续时间,它也不会使用要恢复的数据进行初始化。