You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改C语言strtok实现的split函数,仅保留冒号分隔符

解决方案

要实现仅当分隔符为:时将其追加到分割字符串末尾的需求,不能直接依赖strtok——因为strtok会跳过分隔符且无法告知当前使用的是哪种分隔符。我们需要手动遍历字符串,跟踪每个元素后续的分隔符类型,再决定是否追加:。

以下是修改后的完整代码:

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

char ** split(const char * str, const char * delim)
{
    if (!str || !delim) return NULL;

    const char *p = str;
    int nw = 0;
    int *add_colon = NULL;

    // 第一步:统计分割后的元素数量,并标记哪些元素需要追加冒号
    while (*p) {
        // 跳过开头的所有分隔符
        while (*p && strchr(delim, *p)) {
            p++;
        }
        if (!*p) break; // 已遍历到字符串末尾

        nw++;
        // 定位当前元素的结束位置
        const char *start = p;
        while (*p && !strchr(delim, *p)) {
            p++;
        }
        // 检查当前元素后续的分隔符中是否包含':'
        int need_colon = 0;
        const char *sep = p;
        while (*sep && strchr(delim, *sep)) {
            if (*sep == ':') {
                need_colon = 1;
                break; // 只要遇到':'就标记需要追加
            }
            sep++;
        }
        // 存储标记信息
        add_colon = realloc(add_colon, nw * sizeof(int));
        add_colon[nw - 1] = need_colon;

        p = sep; // 移动指针到当前分隔符段的末尾
    }

    if (nw == 0) {
        free(add_colon);
        return NULL;
    }

    // 第二步:分配字符串数组并填充内容
    char **v = malloc((nw + 1) * sizeof(char *));
    if (!v) {
        free(add_colon);
        return NULL;
    }

    p = str;
    int i = 0;
    while (*p && i < nw) {
        // 跳过前置分隔符
        while (*p && strchr(delim, *p)) {
            p++;
        }
        if (!*p) break;

        const char *start = p;
        while (*p && !strchr(delim, *p)) {
            p++;
        }
        int elem_len = p - start;
        // 计算内存大小:需要追加冒号则多预留1个字节
        int buf_size = elem_len + (add_colon[i] ? 1 : 0) + 1;
        v[i] = malloc(buf_size);
        if (!v[i]) {
            // 内存分配失败,释放已分配的资源
            for (int j = 0; j < i; j++) free(v[j]);
            free(v);
            free(add_colon);
            return NULL;
        }
        // 复制元素内容
        strncpy(v[i], start, elem_len);
        if (add_colon[i]) {
            v[i][elem_len] = ':';
            v[i][elem_len + 1] = '\0';
        } else {
            v[i][elem_len] = '\0';
        }
        i++;

        // 跳过后续分隔符
        while (*p && strchr(delim, *p)) {
            p++;
        }
    }
    v[nw] = NULL; // 设置数组结束标记

    free(add_colon);
    return v;
}

int main() {
    char **words = split(" ici: papa mama", " \t\n:");
    if (words) {
        for (int i = 0; words[i]; i++) {
            printf("%s\n", words[i]);
            free(words[i]); // 释放单个字符串内存
        }
        free(words); // 释放数组内存
    }
    return 0;
}

关键修改点说明

  1. 替换strtok为手动遍历:
    • strtok无法提供分隔符的类型信息,因此我们直接遍历原字符串,定位每个元素的起始/结束位置,同时检查后续分隔符中是否包含:。
  2. 标记需要追加冒号的元素:
    • 在统计元素数量时,额外记录每个元素是否需要追加:,存储在add_colon数组中。
  3. 动态分配内存:
    • 根据元素长度和是否追加冒号,计算所需内存大小,避免内存浪费或溢出。
  4. 内存泄漏防护:
    • 当内存分配失败时,释放已分配的所有资源,避免泄漏;测试完成后也需手动释放字符串数组和单个字符串的内存。

运行上述代码,输入" ici: papa mama"会输出:

ici:
papa
mama

内容的提问来源于stack exchange,提问作者Kiko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 06:12:10