【问题标题】:How does the strtok function in C work? [duplicate]C 中的 strtok 函数是如何工作的? [复制]
【发布时间】:2014-02-01 13:13:18
【问题描述】:

我找到了解释strtok函数的示例程序:

#include <stdio.h>
#include <string.h>

int main ()
{
    char str[] ="- This, a sample string.";
    char * pch;
    printf ("Splitting string \"%s\" into tokens:\n",str);
    pch = strtok (str," ,.-");
    while (pch != NULL)
    {
        printf ("%s\n",pch);
        pch = strtok (NULL, " ,.-");
    }
    return 0;
}

但是,我不明白这是如何工作的。

pch = strtok (NULL, " ,.-"); 怎么可能返回一个新的令牌。我的意思是,我们打电话给strtokNULL。这对我来说没有多大意义。

【问题讨论】:

标签: c strtok


【解决方案1】:

关于strtok 的两件事需要了解。如前所述,它“保持内部状态”。此外,它会弄乱您提供给它的字符串。本质上,它会写入一个'\0',它会在其中找到您提供的令牌,并返回一个指向字符串开头的指针。它在内部维护最后一个令牌的位置;下次你调用它时,它就会从那里开始。

重要的推论是您不能在const char* "hello world"; 类型的字符串上使用strtok,因为当您修改const char* 字符串的内容时会出现访问冲突。

strtok 的“好”之处在于它实际上并不复制字符串——因此您不需要管理额外的内存分配等。但除非您了解上述内容,否则您将无法正确使用它。

示例 - 如果您有 "this,is,a,string",对 strtok 的连续调用将生成如下指针(^ 是返回的值)。请注意,'\0' 是在找到令牌的位置添加的;这意味着源字符串被修改:

t  h  i  s  ,  i  s  ,  a  ,  s  t  r  i  n  g \0         this,is,a,string

t  h  i  s  \0 i  s  ,  a  ,  s  t  r  i  n  g \0         this
^
t  h  i  s  \0 i  s  \0 a  ,  s  t  r  i  n  g \0         is
               ^
t  h  i  s  \0 i  s  \0 a  \0 s  t  r  i  n  g \0         a
                        ^
t  h  i  s  \0 i  s  \0 a  \0 s  t  r  i  n  g \0         string
                              ^

希望它有意义。

【讨论】:

    【解决方案2】:

    strtok 保持内部状态。当您使用非 NULL 调用它时,它会重新初始化自己以使用您提供的字符串。当您使用 NULL 调用它时,它会使用该字符串,并且它当前必须返回下一个令牌的任何其他状态。

    由于strtok 的工作方式,如果您正在编写多线程应用程序,您需要确保链接到C 运行时的多线程版本。这将确保每个线程都为strtok 获得自己的内部状态。

    【讨论】:

      【解决方案3】:

      strtok() 函数在调用之间存储数据。当您使用 NULL 指针调用它时,它会使用该数据。

      来自http://www.cplusplus.com/reference/cstring/strtok/

      找到最后一个标记的点由函数内部保存,以便在下次调用时使用(不需要特定的库实现来避免数据争用)。

      【讨论】:

      • 大多数现代运行时将状态存储在线程本地存储中。这意味着它是线程安全的,但在重入时不安全。
      • 感谢指正。
      【解决方案4】:

      strtok 函数将数据存储在一个内部静态变量中,该变量在所有线程之间共享。

      为了线程安全,您应该使用strtok_r

      来自http://www.opensource.apple.com/source/Libc/Libc-167/string.subproj/strtok.c

      看看static char *last;

      char *
      strtok(s, delim)
          register char *s;
          register const char *delim;
      {
          register char *spanp;
          register int c, sc;
          char *tok;
          static char *last;
      
      
          if (s == NULL && (s = last) == NULL)
              return (NULL);
      
          /*
           * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
           */
      cont:
          c = *s++;
          for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
              if (c == sc)
                  goto cont;
          }
      
          if (c == 0) {       /* no non-delimiter characters */
              last = NULL;
              return (NULL);
          }
          tok = s - 1;
      
          /*
           * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
           * Note that delim must have one NUL; we stop if we see that, too.
           */
          for (;;) {
              c = *s++;
              spanp = (char *)delim;
              do {
                  if ((sc = *spanp++) == c) {
                      if (c == 0)
                          s = NULL;
                      else
                          s[-1] = 0;
                      last = s;
                      return (tok);
                  }
              } while (sc != 0);
          }
          /* NOTREACHED */
      }
      

      【讨论】:

      • strtok_s 在 Windows 上
      猜你喜欢
      • 2020-06-07
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多