Naprogramujte modul pro práci s řetězci. Tento modul exportuje strukturu pro řetězec.
typedef struct
{
char *data;
int len;
} String;Dále struktury String_Builder a
String_Iterator, jejichž položky studenti navrhnou
sami.
String_Builder (dále SB) si lze přestavit jako řetězec,
který možno prodlužovat tiskem na jeho konec. (Funkce s ním pracující
sami zajišťují, aby měl vždy alokován dostatek paměti.) Pro práci s SB
implementujte následující funkce.
//
// Inicializuje sb. Nealokuje žádnou paměť pro uchovávání obsahu.
// Po inicialize SB vypadá, jakoby obsahoval prázdný řetězec.
// (Po převodu na String, viz níže, je výsledek prázdný řetězec.)
void sb_init(String_Builder* sb);
//
// Vytvoří SB jako kopii existujícího řetězce
//
String_Builder sb_from_string(String s);
//
// Neuvolňuje žádnou paměť SB, pouze nastaví jeho položky tak, aby obsah
// SB odpovídal prázdnému řetězci.
//
void sb_clear(String_Builder* sb);
//
// Uvolní paměť, kterou sb používá pro uchování řetězce.
//
void sb_destroy(String_Builder* sb);
//
// Funkce analogická printf ze stdio.h, která tiskne do SB.
// Ve formátovacím řetězci podporuje následující direktivy a typy
// - #i typ int,
// - #S řetězec typu String,
// - #s řetězec typu char*,
// - #c znak typu char,
//
// Dále podporuje speciální znaky '\t', '\n', '\"' jako printf.
//
void sb_printf(String_Builder*, String format, ...);
//
// Transformuje SB na String, jehož data jsou nově alokována (tj. SB lze pořád používat).
//
String sb_clone_to_string(String_Builder sb); Příklad použití
String_Builder sb;
sb_init(&sb);
sb_printf(&sb, "#i #i #s\ndalsi radek", 10, 3, "ahoj svete");
String first = sb_clone_to_string(sb);
sb_clear(&sb);
sb_printf(&sb, "predtim bylo %S", first);
String second = sb_clone_to_string(sb);
sb_destroy(&sb);
//
// předpokládejme, že funkce str_print vytiskne String
// Potom následující
//
str_print(second);
//
// vede k tisku
//
predtim bylo 10 3 ahoj svete
dalsi radekImplementujte následující funkce pro práci s řetězci.
//
// Následující čtyři funkce manuálně ALOKUJÍ paměť pro datové položky řetězců,
// vytváří tak nové kopie.
//
// transformace C řetězce na String a zpět
String str_clone_from_cstring(char *cstring);
char* str_clone_to_cstring(String *);
// vytvoření klonu řetězce
String str_clone(String src);
// spojí řetězce obsažené v poli array (s n prvky) do jednoho,
// přitom je od sebe oddělí pomocí řetězce sep;
String str_join(String array[], int n, String sep);
//
// Funkce uvolní vnitřní paměť řetězce a nastaví jej tak,
// aby vypadal jako prázdný řetězec.
//
void str_destroy(String* src);
//
// Následující tři funkce NEALOKUJÍ paměť pro `data` řetězce, ale jejich položka `data`
// ukazuje do této položky jiného řetězce (nebo na C řetězec).
//
// Vytvoří String z C řetězce
String str_wrap(char* cstring);
// Rozdělí `src` na části oddělené oddělovačem `sep`, a vrátí je jako pole.
// Jejich počet zapíše do n.
String* str_split(String src, String sep, int *n);
// Zepředu a zezadu src odstraní všechny znaky obsažené v cutset
// a výsledný řetězec vrátí jako výsledek.
String str_trim(String src, String cutset);Slouží pro procházení částí řetězce, které jsou odděleny oddělovačem. Lze předpokládat, že během procházení se procházený řetězec nemění. Jsou-li vedle sebe dva oddělovače, bereme to tak, že je mezi nimi prázdný řetězec. Je-li oddělovač na konci nebo začátku řetězce, bereme to tak, že je za nebo před ním prázdný řetězec. Neobsahuje-li řetězec oddělovač, skládá se pouze z jedné části.
//
// inicializuje iterátor pro řetězec src a oddělovač delimiter.
//
String_Iterator si_create(Strint src, String delimiter);
//
// Vrátí 1 a nastaví slice na další část řetězce.
// Pokud už byly projity všechny části řetězce, vrátí 0.
//
int si_next(String_Iterator* s, String *slice);
//
// Restartuje iteraci od začátku
//
void si_restart(String_Iterator* s);Příklad použití. Následující kód
//
// předpokládejme, že funkce str_println vytiskne String a potom znak nového řádku
//
String foo = str_clone_from_cstring("resim-*-domaci-*-ulohu");
String delim = str_clone_from_cstring("-*-");
String_Iterator si = si_create(foo, delim);
String s;
while( si_next(&si, &s) )
{
str_println(s);
}
// tady NENÍ nutné volat str_destroy(&s)vytiskne následující.
resim
domaci
ulohuSoučástí řešení bude i modul s testy, které otestují funkčnost části modulu pro práci s řetězci.
Spouštění testů půjde ovládat pomocí funkce.
//
// spustí testy a vypíše vhodné informace [test prosel/neprosel atd.]
//
void run_tests();Očekává se, že student navrhne rozumné testy, které pokryjí i okrajové případy.
Ze string.h jsou povoleny pouze funkce pro práci s
pamětí (začínají mem); z stdio.h pouze
printf; z stdlib.h funkce pro alokaci a
dealokaci paměti. Dále je povolena assert.h,
math.h a stdarg.h.
Jiné knihovní funkce povoleny nejsou.
Odevzdejte adresář se soubory strings.h,
strings.c (modul pro práci s řetězci), test.c,
test.h (modul s testy), volitelně i soubor README (textový
soubor s případnými dalšími informacemi). Při nedodržení předchozího je
úkol považován za nesplněný.
Moduly musí být z pohledu jazyka C správně strukturovány (např.
soukromé funkce a data jsou static).
Úkol budu kontrolovat s pomocí gcc, sanitizeru a programu valgrind.