C语言标准库未提供内置字符串分割函数,主要通过strtok()实现简单分割(会修改原字符串且非线程安全,需确保字符串存储在可修改数组中而非字面量),线程安全替代方案为strtok_r(),若需保留原字符串则可用strcspn/strspn组合或sscanf解析固定格式,实际使用中应根据场景选择方法:单线程简单任务用strtok(),多线程环境用strtok_r(),保留原字符串用组合方法。

C语言标准库没有直接提供split函数,但提供了几种实用的字符串分割方法。

1. strtok()函数(最常用方法)

函数原型

#include <string.h>
char *strtok(char *str, const char *delim);

使用方法

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

int main() {
    char sentence[] = "Hello,world,this,is,a,test";
    const char delimiters[] = ", ";
    char *token;
    
    // 首次调用,传入原始字符串
    token = strtok(sentence, delimiters);
    
    while (token != NULL) {
        printf("%s\n", token);
        // 后续调用传入NULL
        token = strtok(NULL, delimiters);
    }
    
    return 0;
}

工作原理

  • 首次调用时,传入目标字符串和分隔符
  • 后续调用传入NULL,继续从上次分割位置开始
  • 会将分隔符替换为\0,修改原字符串
  • 自动跳过连续分隔符(如"a,,b"会被分割为"a"和"b")

重要注意事项

  1. 原始字符串必须可修改:不能是字符串字面量(如char *str = "hello";),必须是数组形式(如char str[] = "hello";
  2. 非线程安全:使用静态变量保存分割状态,多线程环境下应使用strtok_r()
  3. 会修改原字符串:分割过程中会将分隔符替换为\0,原字符串会被破坏
  4. 分隔符是集合", "表示逗号和空格都是分隔符

2. 线程安全替代方案:strtok_r()

函数原型

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

使用方法

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

int main() {
    char sentence[] = "Hello,world,this,is,a,test";
    const char delimiters[] = ", ";
    char *token;
    char *saveptr;
    
    // 首次调用,传入原始字符串和saveptr
    token = strtok_r(sentence, delimiters, &saveptr);
    
    while (token != NULL) {
        printf("%s\n", token);
        // 后续调用传入NULL和相同的saveptr
        token = strtok_r(NULL, delimiters, &saveptr);
    }
    
    return 0;
}

优点

  • 线程安全:通过saveptr参数显式保存分割状态
  • 适合多线程环境

3. 不修改原字符串的分割方法

如果需要保留原字符串,可以使用strcspnstrspn函数组合:

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

int main() {
    char sentence[] = "Hello,world,this,is,a,test";
    const char delimiters[] = ", ";
    char *current = sentence;
    char *next;
    
    while ((next = strpbrk(current, delimiters)) != NULL) {
        // 处理当前token(从current到next)
        char token[next - current + 1];
        strncpy(token, current, next - current);
        token[next - current] = '\0';
        printf("%s\n", token);
        
        // 移动到下一个位置
        current = next + 1;
    }
    
    // 处理最后一个token
    if (strlen(current) > 0) {
        printf("%s\n", current);
    }
    
    return 0;
}

4. 其他方法

1. 使用sscanf()解析固定格式字符串

#include <stdio.h>

int main() {
    char str[] = "894529306@qq.com";
    int id;
    char domain[10];
    
    sscanf(str, "%d@%[^.]", &id, domain);
    printf("用户名: %d\n", id);
    printf("邮箱类型: %s\n", domain);
    
    return 0;
}

2. 自定义分割函数

对于更复杂的需求,可以编写自己的分割函数,根据需要处理空字段、多级分割等。

5. 常见问题与解决方案

问题1:字符串字面量导致程序崩溃

// 错误用法
char *str = "hello,world";
strtok(str, ","); // 会导致程序崩溃

解决方案:使用可修改的字符数组

// 正确用法
char str[] = "hello,world";
strtok(str, ",");

问题2:处理连续分隔符

char str[] = "a,,b";
strtok(str, ","); // 会返回"a"和"b",跳过中间的空字符串

解决方案:如果需要保留空字符串,可以使用strsep()函数

总结

方法优点缺点适用场景
strtok()接口简单,高效修改原字符串,非线程安全简单单线程场景
strtok_r()线程安全代码稍复杂多线程环境
strcspn/strspn不修改原字符串代码较长需要保留原字符串的场景
sscanf()适合固定格式解析无法处理任意分隔符解析特定格式数据

在实际开发中,对于简单的字符串分割需求,strtok()仍是很好的选择;在多线程环境或需要保留原字符串时,应选择strtok_r()或使用strcspn/strspn组合。