Druhý bonusový úkol

Uvažujeme strukturu pro řetězec z prvního bonusového úkolu.

typedef struct {
        char*  data;
        size_t len;
} string;

string clone_from_cstring(char *cstring)
{
  string ret = {0};
  ret.len  = strlen(cstring);
  if (ret.len == 0) {
    ret.data = 0;
  }
  else {
    ret.data = malloc(ret.len);
    assert(ret.data);
    memcpy(ret.data, cstring, ret.len);
  }
  return ret;
}

void string_println(string s)
{
        for (int i = 0; i < s.len; i += 1)
        {
                printf("%c", s.data[i]);
        }
        printf("\n");
}

V úkolech je zakázáno používat funkcí z string.h, s výjimkou funkcí memcpy, memmove, memset.

První část úkolu (2 body)

Naprogramujte následující funkci (za její korektní implementaci lze získat 2 body).

string* split_string(string str, char delimiter, int *n);

Funkce rozdělí řetězec str na části oddělené znakem delimiter, ten přitom do žádné části nepatří. Funkce vrátí takto vzniklé řetězce v nově alokovaném poli struktur string, každá z těchto struktur je klonem části původního řetězce, tj. paměť pro pole .data je nově alokována, pointer .data tedy neukazuje do pole str.data. Počet vzniklých řetězců zapíše na adresu n.

Příklady rozdělení řetězce (delimiter je '-')

"ahoj-svete"       -> "ahoj", "svete"
"ahoj--svete"      -> "ahoj", "", "svete"
"-ahoj-svete"      -> "", "ahoj", "svete"
"ahoj-svete-"      -> "ahoj", "svete", ""
"ahoj"             -> "ahoj"

Druhá část úkolu (2 body)

Úkolem je naprogramovat string builder. To je objekt, do kterého se dá tisknout podobně jako na terminál, ale výsledný řetězec je uchováván v paměti. Uvnitř může string builder fungovat podobně jako dynamické pole: když do něj tiskneme a je potřeba řetězec zvětšit, paměť realokujeme.

Předpokládejme následující strukturu pro string builder.

typedef struct
{
    char *data;
    size_t capacity;
    size_t len;
} string_builder;

Za úkol je imlementovat následující funkce.

void sb_allocate(string_builder *sb, size_t capacity);

Alokuje vnitřní paměť na capacity znaků. Funkce je použita pouze při inicializaci prázdného builderu.

void sb_destroy(string_builder *sb);

Uvolní vnitřní pamět a příslušně nastaví položky struktury.

string sb_to_string(string_builder sb);

Vrátí obsah string builderu jako nově vytvořený string, jeho vnitřní data jsou nově alokována.

void sb_print_int(string_builder *sb, int i);
void sb_print_cstring(string_builder *sb, char *cs);

Funkce pro tisk do string builderu.

Ukázka použití:

string_builder sb = {};
sb_allocate(&sb, 5);
sb_print_cstring(&sb, "test ");
sb_print_int(&sb, -3);
sb_print_cstring(&sb, " string builderu");
string str = sb_to_string(sb);
string_println(str);

Kód výše vytiskne řádek:

test -3 string builderu