strtok()如何将字符串拆分为C中的标记?

fud*_*din 101 c string split token strtok

请解释我的strtok()功能工作.手册说它把字符串分成了令牌.我无法从手册中了解它实际上是做什么的.

我添加了手表str*pch检查其工作情况,当第一个while循环发生时,内容str仅为"this".如何在屏幕上显示下面显示的输出?

/* strtok example */
#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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Splitting string "- This, a sample string." into tokens:
This
a
sample
string

And*_*rsK 199

strtok运行时函数的工作原理如下

第一次调用strtok时,您提供了一个要标记的字符串

char s[] = "this is a string";
Run Code Online (Sandbox Code Playgroud)

在上面的字符串空间似乎是单词之间的一个很好的分隔符所以让我们使用:

char* p = strtok(s, " ");
Run Code Online (Sandbox Code Playgroud)

现在发生的是搜索's'直到找到空格字符,返回第一个标记('this')并且p指向该标记(字符串)

为了获得下一个标记并继续使用相同的字符串NULL作为第一个参数传递,因为strtok维护一个指向前一个传递字符串的静态指针:

p = strtok(NULL," ");
Run Code Online (Sandbox Code Playgroud)

p现在指向'是'

等等,直到找不到更多的空格,然后最后一个字符串作为最后一个标记"字符串"返回.

更方便的是你可以像这样写它来打印出所有的标记:

for (char *p = strtok(s," "); p != NULL; p = strtok(NULL, " "))
{
  puts(p);
}
Run Code Online (Sandbox Code Playgroud)

编辑:

如果要存储返回的值,则strtok需要将令牌复制到另一个缓冲区,例如,strdup(p);因为原始字符串(由内部的静态指针指向strtok)在迭代之间被修改以便返回令牌.

  • +1为静态缓冲区,这是我不明白的 (26认同)
  • 它确实取代了''找到'\ 0'.并且,它不会在以后恢复,所以你的字符串会被破坏. (4认同)
  • *“返回第一个标记并且 `p` 指向该标记”* 行中缺少一个非常重要的细节,即 `strtok` 需要通过放置空字符代替分隔符来改变原始字符串(否则其他字符串函数不知道标记在哪里结束)。它还使用静态变量跟踪状态。 (2认同)

Sac*_*hag 36

strtok()将字符串分为标记.即从任何一个分隔符开始到下一个分隔符将是您的一个标记.在您的情况下,起始标记将来自" - "并以下一个空格""结束.然后下一个标记将从""开始,以","结束.在这里你得到"这个"作为输出.类似地,字符串的其余部分从空间分割成令牌,最后在"."上结束最后一个令牌.

  • @fahad - 它只用NUL替换分隔符,而不是分隔符之间的所有字符.它将字符串分成多个标记.你得到"这个",因为它在两个指定的分隔符之间而不是"-this". (2认同)

Joh*_*ode 23

strtok维护一个指向字符串中下一个可用标记的静态内部引用; 如果你传递一个NULL指针,它将从该内部引用.

这是strtok不可重入的原因; 一旦你传递了一个新指针,旧的内部引用就会被破坏.

  • 旧的内部参考“被破坏”是什么意思。您的意思是“覆盖”吗? (2认同)

Mat*_*Mat 10

strtok不会更改参数本身(str).它存储该指针(在本地静态变量中).然后,它可以在后续调用中更改该参数指向的内容,而无需传回参数.(并且它可以推进它保留的指针,但它需要执行其操作.)

从POSIX strtok页面:

此函数使用静态存储来跟踪调用之间的当前字符串位置.

有一个线程安全的variant(strtok_r)不会做这种魔术.

  • 好吧,C库的功能可以追溯到什么时候,线程根本不在图片中(就C标准来说,仅在2011年才开始存在),所以重新入门并不重要(我猜).静态本地使功能"易于使用"(对于"简单"的某些定义).就像`ctime`返回一个静态字符串 - 实用(没有人需要知道谁应该释放它),但如果你不是很了解它就不会重新进入并绊倒你. (2认同)

tib*_*bur 7

第一次调用它时,您提供要标记的字符串strtok.然后,为了得到以下标记,NULL只要它返回一个非NULL指针就可以给该函数.

strtok函数记录您在调用时首先提供的字符串.(这对多线程应用程序来说真的很危险)


Zif*_*ion 6

strtok会对字符串进行标记,即将其转换为一系列子字符串.

它通过搜索分隔这些标记(或子串)的分隔符来实现.并指定分隔符.在你的情况下,你想要''或','或'.' 或' - '作为分隔符.

提取这些令牌的编程模型是您手动执行主字符串和分隔符集.然后你反复调用它,每次strtok都会返回它找到的下一个标记.直到它返回主字符串的末尾,返回null.另一个规则是您只在第一次传递字符串,并在随后的时间传递NULL.如果您要使用新字符串开始新的标记化会话,或者您正在从先前的标记化会话中检索标记,这是一种告诉strtok的方法.请注意,strtok会记住其标记化会话的状态.因此,它不是可重入或线程安全的(您应该使用strtok_r).另一件要知道的是它实际上修改了原始字符串.它为它找到的teh分隔符写'\ 0'.

一种简单地调用strtok的方法如下:

char str[] = "this, is the string - I want to parse";
char delim[] = " ,-";
char* token;

for (token = strtok(str, delim); token; token = strtok(NULL, delim))
{
    printf("token=%s\n", token);
}
Run Code Online (Sandbox Code Playgroud)

结果:

this
is
the
string
I
want
to
parse
Run Code Online (Sandbox Code Playgroud)


xpm*_*teo 5

strtok 修改其输入字符串。它在其中放置空字符 ('\0'),以便将原始字符串的位作为标记返回。实际上 strtok 不分配内存。如果将字符串绘制为一系列框,您可能会更好地理解它。