【问题标题】:Strtok inside strtok not working with copy of original token - C [duplicate]strtok内部的Strtok不能使用原始令牌的副本-C [重复]
【发布时间】:2017-01-12 21:35:46
【问题描述】:

我意识到标题令人困惑,想不出更清晰的措辞。基本上,我在 strtok 循环内调用 strtok 循环,但是当内部 strtok 函数从 runCommand 返回时,我的第一个 strtok 循环停止。它只是退出循环,即使第一个分号后面还有其他参数。当我不调用 runCommand() 时,它会按预期工作,并解析我所有用分号分隔的命令。

这段代码的目标是解析一行以分号分隔的命令,然后解析命令和命令参数,以便稍后进入 execvp。这是我唯一遇到问题的部分。这里是:

void parseCommand(char *userLine) 
{
  if(strchr(userLine, ';'))
  {
    // Get first token
    token = strtok(userLine, ";");
    // Loop through all tokens
    while(token != NULL)
    {
      // Make a copy
      char *copy = malloc(strlen(token) + 1);
      strcpy(copy, token);
      runCommand(copy);
      free(copy);
      printf("process returned!\n");
      token = strtok(NULL, ";");
    }
  }
}
void runCommand(char *token)
{
  char *args[20]; 
  char **command = args;
  //Tokenize each command based on space

  char *temp = strtok(token, " \n");
  while (temp != NULL)
  {
    *command++ = temp;
    temp = strtok(NULL, " \n");
  }
  *command = NULL;
// code for fork and execvp here
}

谁能解释为什么 runCommand 搞砸了我的第一个函数的解析?我真的不明白为什么它不能使用我的原始令牌的副本。可能很简单,但我已经看了太久了?

【问题讨论】:

  • “我在 strtok 循环中调用了 strtok 循环” - 不能这样做。 strtok 的设计很烂。
  • 是的,你不能像那样“递归地”使用strtok——一旦你传递了一个新的、非NULL的参数,它就会完全忘记之前的参数。您必须以广度优先而非深度优先处理您的代币。

标签: c copy token strtok


【解决方案1】:

函数strtok 不可重入。它会记住它的当前状态,这就是为什么你通过NULL 进行重复调用而没有段错误。

考虑使用strtok_sstrtok_r(取决于实现),它允许调用者保存状态。这些可以嵌套使用。

【讨论】:

  • strtok_r 不标准,推荐使用strtok_s
  • 谢谢!!下次我会仔细研究文档。
  • @Olaf:如果您在 Windows 上工作,strtok_s() 是可以使用的,因为它可用。如果你在 Unix 上工作,strtok_s() 不可用——POSIX 拒绝了附件 K 中的函数(有关更多信息,请参阅Do you use the TR24731 'safe' functions)并且基本上没有 Unix 系统实现它们中的任何一个——但strtok_r() 可用。幸运的是,两者在功能上是相同的。除非平台是明确的,否则明确说明 strtok_s()strtok_r() 充其量是……误导。
  • @JonathanLeffler:我不知道他们拒绝了整个附件。有趣的是,其中一些功能仍然可用,但由于strtok_s 似乎没有联机帮助页,它似乎确实丢失了。谢谢(你的)信息。 (IIRC POSIX 仍然基于 C99 甚至 C90,链接页面比 C11 早 3 年。我想知道更新的 POSIX 版本是否会改变这一点)。
  • @Olaf — AFAIK,POSIX 2008 的 2016 年更新将 C 版本保留为 C99。不过我今天还没有验证。
【解决方案2】:

strtok 不知道它正在执行的上下文,它的行为有点全球性。

尝试使用strtok_r,它允许您指定上下文,这样多个单独的使用不会相互干扰。

来自man page

可以使用对指定不同saveptr 参数的strtok_r() 调用序列同时解析不同的字符串。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    • 1970-01-01
    • 2019-02-07
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多