Namespaces
Variants

strtok, strtok_s

From cppreference.net
< c ‎ | string ‎ | byte
定义于头文件 <string.h>
(1)
char * strtok ( char * str, const char * delim ) ;
(C99前)
char * strtok ( char * restrict str, const char * restrict delim ) ;
(C99起)
char * strtok_s ( char * restrict str, rsize_t * restrict strmax,
const char * restrict delim, char ** restrict ptr ) ;
(2) (C11起)

对以空字符结尾的字节字符串进行分词处理。

1) strtok 的一系列调用将 str 所指向的字符串分解为由 delim 所指向字符串中的字符分隔的标记序列。序列中的每次调用都有一个 搜索目标
  • str 非空,该调用是序列中的 首次调用 。搜索目标为 str 所指向的以空字符结尾的字节字符串。
  • str 为空,该调用是序列中的 后续调用 之一。搜索目标由序列中的前次调用确定。
序列中的每次调用都会在搜索目标中查找第一个 包含在由 delim 指向的 分隔符字符串 中的字符,分隔符字符串在每次调用时可以不同。
  • 如果未找到此类字符,则搜索目标中不存在令牌。序列中下一次调用的搜索目标保持不变。 [1]
  • 如果找到此类字符,它将成为当前令牌的起始点。 strtok 随后从该位置开始查找第一个包含在分隔符字符串中的字符。
    • 如果未找到此类字符,当前令牌将延伸至搜索目标末尾。序列中下一次调用的搜索目标为空字符串。 [2]
    • 如果找到此类字符,它将被空字符覆盖,从而终止当前令牌。序列中下一次调用的搜索目标从后续字符开始。
如果 str delim 不是指向以空字符结尾的字节字符串的指针,则行为未定义。
2) (1) 相同,但存在以下差异:
  • 每次调用时,将 str 中剩余可查看的字符数量写入 * strmax ,并将分词器的内部状态写入 * ptr
  • 序列中的后续调用必须使用前次调用存储的值传递 strmax ptr
  • 以下错误会在运行时被检测到,并调用当前安装的 约束处理程序 函数,且不会在 ptr 指向的对象中存储任何内容:
    • strmax delim ptr 是空指针。
    • 序列中的后续调用出现 * ptr 为空指针。
    • * strmax 大于 RSIZE_MAX
    • 找到的词元末尾未出现在搜索目标的前 * s1max 个字符内。
如果 str 指向的字符数组缺少空字符,且 strmax 指向的值大于该字符数组的大小,则行为未定义。
与所有边界检查函数一样,仅当实现定义了 __STDC_LIB_EXT1__ 且用户在包含 <string.h> 之前将 __STDC_WANT_LIB_EXT1__ 定义为整型常量 1 时,才保证 strtok_s 可用。
  1. 在后续使用不同分隔字符串的调用中仍可能形成标记。
  2. 后续调用中无法再形成更多标记。

目录

参数

str - 指向要标记化的以空字符结尾的字节字符串的指针
delim - 指向标识分隔符的以空字符结尾的字节字符串的指针
strmax - 指向一个对象的指针,该对象初始保存 str 的大小: strtok_s 存储剩余待检查的字符数量
ptr - 指向 char * 类型对象的指针, strtok_s 使用它来存储其内部状态

返回值

1) 返回指向下一个令牌首字符的指针,若无令牌则返回空指针。
2) 返回指向下一个令牌首字符的指针,若不存在令牌或发生运行时约束违规则返回空指针。

注意

此函数具有破坏性:它会在字符串 str 的元素中写入 ' \0 ' 字符。特别需要注意的是,字符串字面量不能作为 strtok 的第一个参数使用。

每次调用 strtok 都会修改静态变量:不具备线程安全性。

与大多数其他分词器不同, strtok 中的分隔符对于每个后续标记可以各不相同,甚至可以依赖于先前标记的内容。

strtok_s 函数与 POSIX strtok_r 函数的区别在于:前者能防止在待分割字符串外部存储数据,并会检查运行时约束。Microsoft CRT 的 strtok_s 函数签名符合此 POSIX strtok_r 定义,而非 C11 标准的 strtok_s

示例

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <string.h>
int main(void)
{
    char input[] = "A bird came down the walk";
    printf("Parsing the input string '%s'\n", input);
    char* token = strtok(input, " ");
    while (token)
    {
        puts(token);
        token = strtok(NULL, " ");
    }
    printf("Contents of the input string now: '");
    for (size_t n = 0; n < sizeof input; ++n)
        input[n] ? putchar(input[n]) : fputs("\\0", stdout);
    puts("'");
#ifdef __STDC_LIB_EXT1__
    char str[] = "A bird came down the walk";
    rsize_t strmax = sizeof str;
    const char* delim = " ";
    char* next_token;
    printf("Parsing the input string '%s'\n", str);
    token = strtok_s(str, &strmax, delim, &next_token);
    while (token)
    {
        puts(token);
        token = strtok_s(NULL, &strmax, delim, &next_token);
    }
    printf("Contents of the input string now: '");
    for (size_t n = 0; n < sizeof str; ++n)
        str[n] ? putchar(str[n]) : fputs("\\0", stdout);
    puts("'");
#endif
}

可能的输出:

Parsing the input string 'A bird came down the walk'
A
bird
came
down
the
walk
Contents of the input string now: 'A\0bird\0came\0down\0the\0walk\0'
Parsing the input string 'A bird came down the walk'
A
bird
came
down
the
walk
Contents of the input string now: 'A\0bird\0came\0down\0the\0walk\0'

参考文献

  • C23 标准 (ISO/IEC 9899:2024):
  • 7.24.5.8 strtok 函数 (p: TBD)
  • K.3.7.3.1 strtok_s 函数 (p: TBD)
  • C17 标准 (ISO/IEC 9899:2018):
  • 7.24.5.8 strtok 函数 (p: TBD)
  • K.3.7.3.1 strtok_s 函数 (p: TBD)
  • C11 标准 (ISO/IEC 9899:2011):
  • 7.24.5.8 strtok 函数 (p: 369-370)
  • K.3.7.3.1 strtok_s 函数 (p: 620-621)
  • C99标准(ISO/IEC 9899:1999):
  • 7.21.5.8 strtok函数(页码:332-333)
  • C89/C90 标准 (ISO/IEC 9899:1990):
  • 4.11.5.8 strtok 函数

参阅

在一个字符串中查找另一个字符串中任意字符的首个出现位置
(函数)
返回仅包含不在另一个字节串中找到的字符的最大初始段长度
(函数)
返回仅包含在另一个字节串中找到的字符的最大初始段长度
(函数)
(C95) (C11)
在宽字符串中查找下一个标记
(函数)
C++ 文档 for strtok