我是C#man,C语言的新手第一次使用积分。
此功能可在将来与malloc()
,realloc()
和free()
配合使用:
char ** split(char * delimiter, char * input) {
int i = 0;
int size = sizeof(char *);
char ** tokens;
char * token;
char * state;
tokens = (char **) malloc(size);
if(tokens == NULL) {
printf("Allocation failed.");
return;
}
for(token = strtok_r(input, delimiter, &state);
token != NULL;
token = strtok_r(NULL, delimiter, &state),
i++, size *= i) {
tokens = (char **) realloc(tokens, size);
if(tokens == NULL) {
printf("Realloc failed.");
return;
}
tokens[i] = state;
}
return tokens;
}
我打电话的时候:
char * IPNumber = "127.0.01";
char * delimiter = ".";
char ** parts = split(delimiter, IPNumber);
它提供了segmentation fault
。
我正在寻找解释如何获取(计算)realloc()
函数的第二个参数中使用的大小值的解释。提前致谢。
答案 0 :(得分:2)
你的malloc / calloc的大小是错误的(你乘以预期的数量,这使得数组增长count!
)
在第一项上:i = 0,size = sizeof(char *); 在第二项i = 1,size = sizeof(char)/ *对于两个元素来说太小* /
char ** split(char * delimiter, char * input) {
unsigned size , used;
char ** array = NULL;
char * token;
char * state;
size = used = 0;
for(token=strtok_r(input, delimiter, &state); token; token=strtok_r(NULL, delimiter, &state) ) {
if (used+1 >= size) {
size = size ? 2*size: 4;
array = realloc(array, size * sizeof *array);
if (!array) { printf("Realloc failed."); return NULL ; /*leak here*/ }
}
array[used++] = state;
}
/* NOTE: need a way to communicate the number of elements back to the caller */
if (array) array[used] = NULL;
return array;
}
更新:这是一个测试驱动程序
int main(void)
{
char stuff[] = "this is the stuff";
char **ppp;
unsigned idx;
ppp = split( " " , stuff);
for (idx = 0; ppp && ppp[idx]; idx++) {
fprintf(stdout, "%u: %s\n", idx, ppp[idx] );
}
return 0;
}
答案 1 :(得分:2)
好的,我猜想你想要的是返回一个字符串数组:
char ** split(char * delimiter, char * input) {
int i;
char ** tokens;
char * token;
char * state;
tokens = (char **) malloc(sizeof(char *) * (2));
if(tokens == NULL) {
printf("Allocation failed.");
return NULL;
}
tokens[0]=(char *)1; /* one element populated */
tokens[1]=NULL; /* no tokens */
for(i=1, token = strtok_r(input, delimiter, &state);
token != NULL;
token = strtok_r(NULL, delimiter, &state),
i++) {
/* grow array by one element - originally made with 2 */
{
char **new =(char **) realloc(tokens, (i+2) * sizeof(char *));
if(new == NULL) {
printf("Realloc failed.");
free(tokens);
return NULL;
}
else
{
tokens = new;
tokens[i+1] = NULL; /* initialize new entry */
}
}
tokens[i] = token;
tokens[0] = (char *)i;
}
return tokens;
}
int main( void )
{
char str[] = "129.128.0.1";
char delim[] = ".";
char **ret;
ret = split( delim, str );
printf( "tokens = %d\n", (int)ret[0] );
printf( "tokens[1] = %s\n", ret[1] );
printf( "tokens[2] = %s\n", ret[2] );
printf( "tokens[3] = %s\n", ret[3] );
printf( "tokens[4] = %s\n", ret[4] );
printf( "tokens[5] = %s\n", ret[5] );
}
答案 2 :(得分:0)
完成重写。发布的原始代码存在一些问题。
因此,我不会尝试描述更改,而是按照与其他模式相同的模式,并根据最大可能的令牌数量显示可能是一个更简洁的实现。
char ** split(char * delimiter, char * input) {
int size;
int maxsize;
char ** tokens;
char * token;
char * state;
// compute max possible tokens, which is half the input length.
// Add 1 for the case of odd strlen result and another +1 for
// a NULL entry on the end
maxsize = strlen( input ) / 2 + 2;
tokens = (char**)malloc( maxsize * sizeof( char*) );
if(tokens == NULL) {
printf("Allocation failed.");
return NULL;
}
size = 0;
for(token = strtok_r(input, delimiter, &state);
token != NULL;
token = strtok_r(NULL, delimiter, &state) ) {
tokens[size++] = token;
}
assert( size < maxsize );
// Put a NULL in the last entry so the caller knows how many entries
// otherwise some integer value would need to be returned as an output
// parameter.
tokens[size] = NULL;
// NOTE: could use realloc from maxsize down to size if desired
return tokens;
}
用法可能如下所示。注意使用strdup
来避免将字符串常量传递给函数:
char * IPNumber = strdup( "127.0.01" );
char * delimiter = ".";
char ** parts = split(delimiter, IPNumber);
int i;
if ( parts ) {
for ( i = 0; parts[i] != NULL; i++ )
printf( "%s\n", parts[i] );
free( parts );
}
free( IPNumber );
答案 3 :(得分:0)
我打算指出需要解决的问题,但只需按照以下步骤重写:
char **split(char *delim, char *input)
{
char *save; /* saved state for strtok_r */
char **tmp, /* temporary result from realloc (for error handling) */
**res; /* result - NULL-terminated array of tokens */
int i, /* index of current/last token */
count; /* number of elements in res (including NULL) */
/* Allocate first element for res */
if ( !(res = malloc(sizeof(res[0]))) ) {
/* return NULL if malloc() fails */
fprintf(stderr,"split(): malloc() failed\n");
return NULL;
}
/* res[0] = first token, or NULL */
res[0] = strtok_r(input,delim,&save);
/* if it was a token, grab the rest. Last one will be the NULL
* returned from strtok_r() */
if (res[0])
i = 0;
count = 1;
do {
/* Resize res, for next token */
/* use a temporary pointer for realloc()'s result, so that
* we can check for failure without losing the old pointer */
if ( tmp = realloc(res, sizeof(res[0]) * ++count) )
res = tmp;
else {
/* if realloc() fails, free res and return NULL */
free(res);
fprintf(stderr,"split(): realloc() failed.\n");
return NULL;
}
/* get next token, or NULL */
res[++i] = strtok_r(NULL,delim,&save);
} while (res[i]); /* done when last item was NULL */
return res;
}
因此realloc的大小是所需元素的数量,乘以元素的大小。
以上版本的代码返回以NULL结尾的数组。另一种方法是以某种方式返回数组元素的数量(例如通过int *
或size_t *
参数);但无论如何,你需要一种让调用者知道结果数组结束位置的方法。
使用strtok_r()
也会增加另一个问题:原始input
字符串不保持不变。因此,在使用此(或原始)函数时,您需要牢记这一点 - 当您不需要保留原始字符串时使用它,或者首先复制原始字符串。