如何修改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; }
关键修改点说明
- 替换
strtok为手动遍历:strtok无法提供分隔符的类型信息,因此我们直接遍历原字符串,定位每个元素的起始/结束位置,同时检查后续分隔符中是否包含:。
- 标记需要追加冒号的元素:
- 在统计元素数量时,额外记录每个元素是否需要追加
:,存储在add_colon数组中。
- 在统计元素数量时,额外记录每个元素是否需要追加
- 动态分配内存:
- 根据元素长度和是否追加冒号,计算所需内存大小,避免内存浪费或溢出。
- 内存泄漏防护:
- 当内存分配失败时,释放已分配的所有资源,避免泄漏;测试完成后也需手动释放字符串数组和单个字符串的内存。
运行上述代码,输入" ici: papa mama"会输出:
ici: papa mama
内容的提问来源于stack exchange,提问作者Kiko
相关产品推荐
相关产品推荐

