0Pricing
C Academy · 课时

strtok 与分词

拆分字符串

strtok 与分词 是 CoddyKit 上的免费 C Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

什么是分词?

分词是指根据分隔符字符,将字符串拆分成更小的片段(词元)。

例如,将 "a,b,c" 按逗号拆分,会得到词元 a、b 和 c。C 提供了 strtok 来完成此操作。

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

int main(void) {
    char text[] = "a,b,c";
    char *token = strtok(text, ",");
    printf("First token: %s\n", token);
    return 0;
}

strtok 的函数声明

char *strtok(char *str, const char *delim);

在第一次调用时传入字符串。在后续调用中传入 NULL,这样它就会从上次停止的位置继续。完成后,它会返回下一个词元;如果已经结束,则返回 NULL。

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

int main(void) {
    char text[] = "red green blue";
    char *tok = strtok(text, " ");
    while (tok != NULL) {
        printf("%s\n", tok);
        tok = strtok(NULL, " ");
    }
    return 0;
}

strtok 会修改字符串

请注意:strtok 会更改原始字符串。它会将每个分隔符替换为 '\0',并返回指向同一缓冲区的指针。

这意味着您不能对字符串字面量(例如 "a,b")进行分词,因为它是只读的。

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

int main(void) {
    char data[] = "x:y:z";
    strtok(data, ":");
    printf("data[1] is now: %d (the null byte)\n", data[1]);
    return 0;
}

创建可写副本

由于 strtok 会破坏其输入,如果之后还需要使用原字符串,请先复制它。

您可以使用本地 char 数组,或使用 strcpy 将字符串复制到缓冲区中。

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

int main(void) {
    const char *original = "one-two-three";
    char copy[64];
    strcpy(copy, original);
    char *tok = strtok(copy, "-");
    while (tok) {
        printf("%s\n", tok);
        tok = strtok(NULL, "-");
    }
    printf("Original intact: %s\n", original);
    return 0;
}

多个分隔符

delim 参数表示一个字符集合,而不是一个序列。集合中的任何字符都可作为分隔符。

因此," ,;" 会同时按空格、逗号和分号进行拆分。

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

int main(void) {
    char text[] = "a,b;c d";
    char *tok = strtok(text, ",; ");
    while (tok) {
        printf("[%s]\n", tok);
        tok = strtok(NULL, ",; ");
    }
    return 0;
}

连续的分隔符

strtok 会将连续出现的分隔符视为一个分隔符,并跳过空词元。

因此,"a,,b" 只会得到 a 和 b,中间不会有空词元。在解析 CSV 时,空字段可能很重要,请牢记这一点。

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

int main(void) {
    char text[] = "a,,b";
    char *tok = strtok(text, ",");
    while (tok) {
        printf("token: %s\n", tok);
        tok = strtok(NULL, ",");
    }
    return 0;
}

统计词元数量

一个常见任务是统计字符串包含多少个词元。请在循环中递增计数器。

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

int main(void) {
    char sentence[] = "the quick brown fox";
    int count = 0;
    char *tok = strtok(sentence, " ");
    while (tok) {
        count++;
        tok = strtok(NULL, " ");
    }
    printf("Word count: %d\n", count);
    return 0;
}

strtok 会保存隐藏状态

strtok 会将当前位置存储在一个静态内部变量中。这就是为什么传入 NULL 后可以继续处理上一个字符串。

缺点是:它不可重入,也不是线程安全的。您不能同时对两个字符串进行分词。

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

int main(void) {
    char a[] = "1 2";
    char *t = strtok(a, " ");
    printf("%s\n", t);
    t = strtok(NULL, " ");
    printf("%s\n", t);
    return 0;
}

保存词元

如果需要在拆分后继续使用词元,请将返回的指针存储在数组中。它们指向已被修改的源缓冲区,因此该缓冲区必须保持有效。

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

int main(void) {
    char csv[] = "name,age,city";
    char *fields[10];
    int n = 0;
    char *tok = strtok(csv, ",");
    while (tok && n < 10) {
        fields[n++] = tok;
        tok = strtok(NULL, ",");
    }
    for (int i = 0; i < n; i++)
        printf("Field %d: %s\n", i, fields[i]);
    return 0;
}

可重入的替代方案

POSIX 提供了 strtok_r。它会显式接收 char **saveptr,而不是使用隐藏状态。因此可以安全地嵌套调用,并在多个线程中使用。

对于可移植的标准 C,普通的 strtok 足以完成单遍解析。

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

int main(void) {
    char text[] = "p:q:r";
    char *save;
    char *tok = strtok_r(text, ":", &save);
    while (tok) {
        printf("%s\n", tok);
        tok = strtok_r(NULL, ":", &save);
    }
    return 0;
}

实践:拆分路径

解析文件路径等结构化文本时,分词功能非常实用。按 / 拆分可以得到路径中的每个组成部分。

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

int main(void) {
    char path[] = "usr/local/bin";
    char *part = strtok(path, "/");
    while (part) {
        printf("-> %s\n", part);
        part = strtok(NULL, "/");
    }
    return 0;
}

快速检查

请测试您对 strtok 工作方式的理解。

回顾

您已经学习了如何使用 strtok 拆分字符串:

  • 第一次调用接收字符串;后续调用接收 NULL。
  • 它会修改输入,将分隔符替换为 '\0'——请先复制只读字符串。
  • 分隔符参数是一个集合;连续的分隔符会合并处理。
  • 它使用静态状态,并且不是线程安全的;需要时请使用 strtok_r。

常见问题解答

「strtok 与分词」课时是免费的吗?

是的 — 「strtok 与分词」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「strtok 与分词」这节课中我会学到什么?

拆分字符串 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「strtok 与分词」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. strlen、strcpy、strcat
  2. strcmp 与比较
  3. strtok 与分词
  4. memcpy 与 memset
← 返回 C Academy