У меня есть некоторые оговорки относительно кода, но это работает чисто под valgrind
(никаких утечек, без злоупотреблений). Я оставил подфункции в основном неизменными, за исключением того, что постоянные строки отмечены константой. Код в split()
был упрощен. Как я отметил в комментарии, я предлагаю написать основную функцию split()
, чтобы у вас был локальный char **string_list;
, который вы выделяете и заполняете. Затем, когда вы собираетесь вернуться, вы назначаете *target = string_list;
. Это облегчит вам понимание того, что происходит. Тройная косвенность противна. Вы можете обосновать это здесь (просто), но свести к минимуму время, затрачиваемое на тройные указатели. Пересмотр принимает эту стратегию.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int split(const char *source, char ***target, const char *splitStr);
static int
indexOf(const char *source, const char *template)
{
int i;
int j;
int index;
for (i = 0; source[i]; i++)
{
index = i;
for (j = 0; template[j]; j++)
{
if (source[i + j] != template[j])
{
index = -1;
break;
}
}
if (index != -1)
return index;
}
return -1;
}
static int
charcount(const char *source, const char *countChar)
{
int count = 0;
for (int i = 0; source[i]; i++)
{
if (source[i] == countChar[0])
count++;
}
return count;
}
static char *
substring(const char *source, int start, int length)
{
char *target = (char *)malloc(length + 1);
if (target != 0)
{
memmove(target, source + start, length);
target[length] = '\0';
}
return target;
}
int
split(const char *source, char ***target, const char *splitStr)
{
int splitCount = charcount(source, splitStr) + 1;
char **result = (char **)malloc(splitCount * sizeof(*result));
if (result == 0)
return -1;
int splitLength = strlen(splitStr);
char **next = result;
const char *currentSubstring = source;
for (int i = 0; i < splitCount; i++)
{
int splitCharPosition = indexOf(currentSubstring, splitStr);
if (splitCharPosition < 0)
break;
*next++ = substring(currentSubstring, 0, splitCharPosition);
currentSubstring += splitCharPosition + splitLength;
}
*next++ = substring(currentSubstring, 0, strlen(currentSubstring));
*target = result;
return (next - result); /* Actual number of strings */
}
static void print_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
{
if (strings[i] != 0)
printf("%d: <<%s>>\n", i, strings[i]);
}
}
static void free_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
free(strings[i]);
free(strings);
}
int main(void)
{
const char source[] = "This is a string; it is really!";
char **strings;
int nstrings;
nstrings = split(source, &strings, " ");
printf("Splitting: <<%s>> on <<%s>>\n", source, " ");
print_list(nstrings, strings);
free_list(nstrings, strings);
nstrings = split(source, &strings, "is");
printf("Splitting: <<%s>> on <<%s>>\n", source, "is");
print_list(nstrings, strings);
free_list(nstrings, strings);
return 0;
}
Заметим, что во втором примере, charcount()
возвращает 6, но есть только четыре строки. Это привело к поздней корректировке исходного кода. (Вы могли бы realloc()
result
, так что это точно правильный размер, но, вероятно, не стоит беспокоиться о том, если расхождение действительно отмечено - скажем, «более 10 записей».) Обработка ошибок не идеальна; он не получает доступ к недопустимой памяти после сбоя, но также не останавливается на попытке выделить. Также он не сообщает о сбоях в распределении отдельных строк - он делает это для отказа выделить массив указателей.
я бы, вероятно, избежать тройной указатель, создавая структуру:
typedef struct StringList
{
size_t nstrings;
char **strings;
} StringList;
Вы можете передать указатель на один из них в split()
, и в функции полезности, такие как free_list()
и print_list()
. Функция free_list()
затем изменит структуру так, чтобы оба элемента были обнулены после того, как данные, на которые указывает структура, освобождены.
Я также был бы соблазн использовать другую реализацию indexOf()
:
int indexOf(const char *haystack, const char *needle)
{
const char *pos = strstr(haystack, needle);
if (pos != 0)
return (pos - haystack);
return -1;
}
Вы получаете upvote за упоминание, что вы использовали отладчик, прежде чем прийти сюда, чтобы опубликовать свой вопрос. – austin
Что делает indexOf()? – Otaia
Это может быть только я, но я чувствую, что этот код слишком сложный для того, чего он пытается достичь. – user1751547