有什么办法可以将带有分隔符的 CONST char * 拆分成数组吗?
Is there any way to split a CONST char * with a delimiter into an array?
我正在尝试将给定的字符串(输入)拆分为一个元素数组。这是我的代码:
char *buff = save_to_buff(); // save the input
int token_count = 1;
for(int i = 0; buff[i] != '[=10=]';i++)
{
if(buff[i] == ' ')
{
token_count++;
}
}
char *token = strtok(buff, " ");
char *arr[token_count];
for(int i = 0;token != NULL;i++)
{
arr[i] = token;
token = strtok(NULL, " ");
}
for(int i = 0; i < token_count;i++)
{
printf("%s ", arr[i]);
}
它有效,但是我需要创建一个函数 char **parse_cmdline(const char *cmdline) 将这种情况下的 buff(cmdline) 拆分为一个数组,但是如果甚至有可能吗?我要么收到 'const' 限定符被丢弃的警告,要么收到错误。有什么办法吗?
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
保存对 realloc
ed 内存的引用,result[0]
对 malloc
ed.
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;
}
您可以将函数拆分为两个函数。
第一个将 return 给定字符串中的标记数。使用函数的 return 值,您可以分配一个指针数组,其元素数等于给定字符串中的标记数加一。那就是令牌数组将以空指针结尾。
第二个函数将用给定字符串的标记填充提供的数组。
这里有一个演示程序。
#include <stdio.h>
#include <string.h>
size_t count_tokens( const char *s1, const char *s2 )
{
size_t n = 0;
while (*s1)
{
s1 += strspn( s1, s2 );
if (*s1)
{
++n;
s1 += strcspn( s1, s2 );
}
}
return n;
}
size_t get_tokens( char **s1, const char *s2, const char *s3 )
{
size_t n = 0;
while (*s2)
{
s2 += strspn( s2, s3 );
if (*s2)
{
++n;
const char *p = s2;
s2 += strcspn( s2, s3 );
size_t len = s2 - p;
*s1 = malloc( len + 1 );
if (*s1)
{
memcpy( *s1, p, len );
( *s1 )[len] = '[=10=]';
}
++s1;
}
}
*s1 = NULL;
return n;
}
int main( void )
{
const char *s1 = "Hello World!";
size_t n = count_tokens( s1, " " );
printf( "%zu\n", n );
char **p = malloc( ( n + 1 ) * sizeof( char * ) );
get_tokens( p, s1, " " );
for ( size_t i = 0; i < n; i++ )
{
if ( p[i] ) puts( p[i] );
}
for (size_t i = 0; i < n; i++)
{
free( p[i] );
}
free( p );
}
程序输出为
2
Hello
World!
作为标记的分隔符,您可以将任何字符串传递给函数,例如 " \t\n'
。
我正在尝试将给定的字符串(输入)拆分为一个元素数组。这是我的代码:
char *buff = save_to_buff(); // save the input
int token_count = 1;
for(int i = 0; buff[i] != '[=10=]';i++)
{
if(buff[i] == ' ')
{
token_count++;
}
}
char *token = strtok(buff, " ");
char *arr[token_count];
for(int i = 0;token != NULL;i++)
{
arr[i] = token;
token = strtok(NULL, " ");
}
for(int i = 0; i < token_count;i++)
{
printf("%s ", arr[i]);
}
它有效,但是我需要创建一个函数 char **parse_cmdline(const char *cmdline) 将这种情况下的 buff(cmdline) 拆分为一个数组,但是如果甚至有可能吗?我要么收到 'const' 限定符被丢弃的警告,要么收到错误。有什么办法吗?
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
保存对 realloc
ed 内存的引用,result[0]
对 malloc
ed.
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;
}
您可以将函数拆分为两个函数。
第一个将 return 给定字符串中的标记数。使用函数的 return 值,您可以分配一个指针数组,其元素数等于给定字符串中的标记数加一。那就是令牌数组将以空指针结尾。
第二个函数将用给定字符串的标记填充提供的数组。
这里有一个演示程序。
#include <stdio.h>
#include <string.h>
size_t count_tokens( const char *s1, const char *s2 )
{
size_t n = 0;
while (*s1)
{
s1 += strspn( s1, s2 );
if (*s1)
{
++n;
s1 += strcspn( s1, s2 );
}
}
return n;
}
size_t get_tokens( char **s1, const char *s2, const char *s3 )
{
size_t n = 0;
while (*s2)
{
s2 += strspn( s2, s3 );
if (*s2)
{
++n;
const char *p = s2;
s2 += strcspn( s2, s3 );
size_t len = s2 - p;
*s1 = malloc( len + 1 );
if (*s1)
{
memcpy( *s1, p, len );
( *s1 )[len] = '[=10=]';
}
++s1;
}
}
*s1 = NULL;
return n;
}
int main( void )
{
const char *s1 = "Hello World!";
size_t n = count_tokens( s1, " " );
printf( "%zu\n", n );
char **p = malloc( ( n + 1 ) * sizeof( char * ) );
get_tokens( p, s1, " " );
for ( size_t i = 0; i < n; i++ )
{
if ( p[i] ) puts( p[i] );
}
for (size_t i = 0; i < n; i++)
{
free( p[i] );
}
free( p );
}
程序输出为
2
Hello
World!
作为标记的分隔符,您可以将任何字符串传递给函数,例如 " \t\n'
。