const 对象无法修改。这是未定义的行为。在使用 strtok 之前,您需要制作字符串的可修改副本。
char **split(const char *restrict str, const char *restrict delim)
{
char **result = NULL;
char *copy;
size_t ntokensLen;
if(str && delim && *str && *delim)
{
copy = malloc(ntokensLen = strlen(str + 1));
if(copy)
{
char *token;
memcpy(copy, str, ntokensLen + 1);
ntokensLen = 0;
token = strtok(copy, delim);
if(!token) free(copy);
while(token)
{
char **tmp;
tmp = realloc(result, (ntokensLen + 2) * sizeof(*tmp));
if(!tmp) { /* error hanling */}
result = tmp;
result[ntokensLen] = token;
result[ntokensLen + 1] = NULL;
token = strtok(NULL, delim);
ntokensLen++;
}
}
}
return result;
}
int main(void)
{
const char *str = "This!is string ^to test...";
char **result = split(str, "! ^.");
size_t cnt = 0;
while(result[cnt])
{
printf("result[%zu] = `%s`\n", cnt, result[cnt]);
cnt++;
}
// how to free?
free(result[0]);
free(result);
}
编辑:
添加了如何释放。 result 持有对 realloced 内存的引用,result[0] 到 malloced。
result 是 NULL 指针终止。
其他拆分版本:
char **mystrtok(const char *str, const char *del, int alowempty)
{
char **result = NULL;
const char *end = str;
size_t size = 0;
int extrachar;
while(*end)
{
if((extrachar = !!strchr(del, *end)) || !*(end + 1))
{
/* add temp variable and malloc / realloc checks */
/* free allocated memory on error */
if(!(!alowempty && !(end - str)))
{
extrachar = !extrachar * !*(end + 1);
result = realloc(result, (++size + 1) * sizeof(*result));
result[size] = NULL;
result[size -1] = malloc(end - str + 1 + extrachar);
strncpy(result[size -1], str, end - str + extrachar);
result[size -1][end - str + extrachar] = 0;
}
str = end + 1;
}
end++;
}
return result;
}
调用者提供的双指针
char **split(char **argv, int *argc, const char *str, const char *delimiter, int allowempty)
{
char *string = malloc(strlen(str + 1));
strcpy(string, str);
*argc = 0;
do
{
if(*string && (!strchr(delimiter, *string) || allowempty))
{
argv[(*argc)++] = string;
}
while(*string && !strchr(delimiter, *string)) string++;
if(*string) *string++ = 0;
if(!allowempty)
while(*string && strchr(delimiter, *string)) string++;
}while(*string);
return argv;
}