Я собирался указать на вещи, которые нужно исправить, но вместо этого просто переписал это следующим образом:
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 - это количество необходимых элементов, умноженное на размер элемента.
Приведенная выше версия кода возвращает массив с нулевым символом в конце.Другой подход заключается в том, чтобы как-то вернуть количество элементов массива (например, с помощью аргумента int *
или size_t *
);но в любом случае вам нужно, чтобы вызывающая сторона знала, где находится конец массива результатов.
Использование strtok_r()
для этого также добавляет еще один улов: исходная строка input
равна , а не осталось без изменений.Поэтому вам необходимо помнить об этом и при использовании этой (или исходной) функции - либо используйте ее, когда вам не нужно сохранять исходную строку, либо сначала создайте дубликат оригинала.