?
Wutz schrieb:
*a=realloc(*a,++r*sizeof**a);
memcpy((*a)[r-1]=calloc(1,i+1),s,i);
Jupp, wer braucht schon Fehlerbehandlung.
Ich schlage vor, hier etwas tiefer in die Trickkiste zu greifen. Der Ansatz ist etwas komplexer, dafür ist er schneller und die Umsetzung einfacher. Der Plan ist, den Array-Kopf, den Index und die Daten direkt hintereinander in einen großen Speicherblock zu legen, d.h.
| size | data | i1 | i2 | i3 | ... | "foo" | "bar" | "baz" | ... |
+------+------+----+----+----+-----+-------+-------+-------+-----+
|___^ | | | ^ ^ ^
|____|____|_________| | |
|____|_________________| |
|_________________________|
Dadurch, dass nur einmal Speicher angefordert wird, entfällt die Fehlerbehandlung bei Speichermangel praktisch vollständig. Das sieht dann etwa so aus:
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct string_array {
size_t size;
char **data;
};
size_t count_tokens(char const *input, size_t n, char delim) {
size_t result = 1;
char const *p;
for(p = input; (p = memchr(p, delim, n - (p - input))); ++p) {
++result;
}
return result;
}
struct string_array *split_string(char const *input, char delim) {
size_t len = strlen(input) + 1;
size_t token_count = count_tokens(input, len, delim);
struct string_array *result = malloc(sizeof(struct string_array) + /* Array-Kopf*/
sizeof(char*) * (token_count) + /* Index */
len); /* Daten */
if(result != NULL) {
char *p;
size_t i;
/* Hier: Der Index liegt direkt hinter dem Kopf im Speicher, die Strings
* direkt hinter dem Index. */
result->size = token_count;
result->data = (char**)(result + 1);
result->data[0] = (char*)(result->data + token_count);
/* Also legen wir die Daten in den gewünschten Bereich */
p = result->data[0];
memcpy(p, input, len);
/* Und ersetzen alle Trenner durch Null-Terminatoren, so dass aus den
* Token einzelne C-Strings werden. Das Vorgehen ist vergleichbar mit
* strtok, allerdings mit nur einem Trennerzeichen und ohne
* aufeinanderfolgende Trenner zu überspringen. */
for(i = 1; i < token_count; ++i) {
p = memchr(p, delim, len - (p - result->data[0]));
*p++ = '\0';
/* Der Index wird hier gebaut. */
result->data[i] = p;
}
}
return result;
}
int main(void) {
size_t i;
struct string_array *a = split_string("foo;bar;baz;qux;;quux;xyzzy", ';');
if(a == NULL) {
return -1;
}
for(i = 0; i < a->size; ++i) {
puts(a->data[i]);
}
free(a);
return 0;
}