OP использует параметр 4 *, но другие подходы лучше.
Высокая степень *
s маскирует отказ ключа заключается в том, что код должен передавать ширину столбца (количество вкладок)
Кроме того, я не вижу определенного нулевого символа завершения в формировании _strings_, поскольку 2-й memcpy()
неограничен по размеру - может даже перезаписать границы выделения.
Идея ниже заключается в том, что каждый уровень выделения заканчивается нулем.
csv = parse_file_string(const char *file_string);
При возврате, когда csv[line] == NULL
, строк больше нет
Когда csv[line][tab] == NULL
, там больше не являются строками.
Этот подход также позволяет использовать другое количество строк в строке.
Скорректированный алгоритм, псевдо C код
// return NULL on error
char ***parse_file_string(const char *file_string) {
number_lines = find_line_count(file_string);
char ***csv = calloc(number_lines + 1, sizeof *csv);
if (csv == NULL) return NULL;
for (line=0; line < number_lines; line++) {
tab_count = find_tab_count(file_string);
csv[line] = calloc(tab_count + 2, sizeof *(csv[line]));
// add NULL check
for (tab=0; tab < tab_count; tab++) {
char *end = strchr(file_string, '\t');
csv[line][tab] = malloc_string(file_string, end);
// add NULL check
file_string = end + 1;
}
char *end = strchr(file_string, '\n');
csv[line][tab++] = malloc_str(file_string, end);
// add NULL check
file_string = end + 1;
csv[line][tab] = NULL;
}
csv[line] = NULL;
return csv;
}
Использование
char ***container = parse_file_string(file_string);
for (line=0; container[line]; line++)
for (tab=0; container[line][tab]; tab++)
puts(container[line][tab]);
//free
for (line=0; container[line]; line++)
for (tab=0; container[line][tab]; tab++)
free(container[line][tab]);
free(container[line]);
free (container)