C语言strtok()函数用法详解!

strtok 是 C 标准库中的字符串分割函数,用于将一个字符串拆分成多个部分(token),以某些字符(称为分隔符)为界限。


函数原型

char *strtok(char *str, const char *delim);
  • 参数

    • str:待分割的字符串。如果是第一次调用,传入要分割的字符串;之后的调用需传入 NULL,以继续上一次的分割。
    • delim:字符串,包含所有分隔符的字符集合。例如," "(空格)或 "/"(斜杠)
  • 返回值

    • 返回指向字符串中 当前部分 的指针。
    • 如果没有更多部分可返回,返回 NULL

用法规则

  1. 初次调用时,传入字符串 str,函数会从 str 中找到第一个部分。
  2. 函数会用 '\0' 替换找到的分隔符(破坏原字符串)。
  3. 后续调用时,传入 NULL,函数会继续从上次结束的位置查找下一部分。
  4. 不能在多线程环境中使用,因为 strtok 使用的是静态变量保存状态。

示例

#include 
#include 

int main() {
    char str[] = "C programming is fun";
    const char *delim = " "; // 用空格作为分隔符
    char *token;

    // 初次调用 strtok
    token = strtok(str, delim);
    while (token != NULL) {
        printf("%s\n", token); // 打印分割的每一部分
        token = strtok(NULL, delim); // 后续调用
    }

    return 0;
}

输出

C
programming
is
fun

注意事项

  1. 原字符串被修改strtok 会在分隔符处插入 '\0',因此原字符串内容会被破坏。如果需要保留原字符串,请先复制到一个新字符串再操作。

  2. 不能并发使用:由于 strtok 使用内部静态变量保存状态,它在多线程程序中不安全。多线程环境下,请使用 strtok_r


分隔符的处理

分隔符 delim 可以包含多个字符,strtok 会将所有出现在 delim 中的字符视为分隔符。例如:

#include 
#include 

int main() {
    char str[] = "apple;orange,banana|grape";
    const char *delim = ";,|"; // 多个分隔符
    char *token;

    token = strtok(str, delim);
    while (token != NULL) {
        printf("%s\n", token);
        token = strtok(NULL, delim);
    }

    return 0;
}

输出

apple
orange
banana
grape

如何在多线程中使用?

在多线程环境下,使用 strtok_r(线程安全版本)。函数原型如下:

char *strtok_r(char *str, const char *delim, char **saveptr);

参数说明

  • str:首次调用传入要分割的字符串,后续调用传入 NULL
  • delim:分隔符集合。
  • saveptr:保存分割状态的指针变量,需由调用者提供。

示例

#include 
#include 

int main() {
    char str[] = "apple;orange,banana|grape";
    const char *delim = ";,|";
    char *token;
    char *saveptr; // 保存状态

    token = strtok_r(str, delim, &saveptr);
    while (token != NULL) {
        printf("%s\n", token);
        token = strtok_r(NULL, delim, &saveptr);
    }

    return 0;
}

输出

apple
orange
banana
grape

为什么需要传入 NULL

strtok 函数内部使用了一个 静态指针 来记录分割状态。这个静态指针会指向原字符串中上一次分割结束的位置。在首次调用时,strtok 初始化这个指针为传入的字符串地址。在后续调用时,通过传入 NULLstrtok 会继续从这个内部静态指针的位置接着分割。


静态指针的工作原理

  1. 初次调用

    token = strtok(str, delim);
    
    • 参数 str 是待分割字符串。
    • strtok 将分隔符替换为 '\0',并返回找到的第一个分割部分,同时保存分割结束的位置到静态指针中。
  2. 后续调用

    token = strtok(NULL, delim);
    
    • 参数 NULL 告诉 strtok 使用保存的静态指针,从上次分割结束的位置继续分割。
    • 每次分割后,strtok 会更新静态指针的位置。

示例分析

#include 
#include 

int main() {
    char str[] = "C,programming,is,fun";
    const char *delim = ",";
    char *token;

    // 初次调用 strtok
    token = strtok(str, delim);
    printf("First token: %s\n", token); // 输出 "C"

    // 后续调用 strtok
    token = strtok(NULL, delim);
    printf("Second token: %s\n", token); // 输出 "programming"

    token = strtok(NULL, delim);
    printf("Third token: %s\n", token); // 输出 "is"

    token = strtok(NULL, delim);
    printf("Fourth token: %s\n", token); // 输出 "fun"

    token = strtok(NULL, delim);
    printf("Final token: %s\n", token); // 输出 "(null)",分割完成

    return 0;
}

输出

First token: C
Second token: programming
Third token: is
Fourth token: fun
Final token: (null)

内部指针变化

  1. 初次调用:
    • str"C,programming,is,fun"
    • 静态指针保存分割后的位置 "programming,is,fun"
  2. 第二次调用:
    • 使用静态指针继续分割。
    • 静态指针更新为 "is,fun"
  3. 第三次调用:
    • 静态指针更新为 "fun"
  4. 第四次调用:
    • 静态指针更新为 NULL

静态指针的局限性

1. 线程不安全

strtok 的静态指针是全局共享的,多个线程同时调用 strtok 会导致状态混乱。

解决方案:使用线程安全的 strtok_r 函数,它将状态保存到用户提供的指针(而非静态变量)中。

2. 不能同时分割多个字符串

因为 strtok 的静态指针只能记录一个字符串的分割状态。如果需要同时分割多个字符串,应使用其他方法(如 strtok_r 或自定义逻辑)。


总结

  • strtok 用于字符串分割,但会修改原字符串,并且线程不安全。
  • 多线程环境下,推荐使用 strtok_r
  • 分割的字符串存储在原字符串中,指针返回的是分割后的部分,原字符串会被破坏。

你可能感兴趣的:(C/C++,c语言,linux,算法)