na obsah klávesové zkratky na hlavní stránku na menu

Řetězce v jazyce C

S řetězci se v jazyce C pracuje jako s poli. Máme mnoho funkcí pro práci s řetězci. Tento článek přináší krátký úvod do práce s řetězci.

Inicializace řetězce

Řetězce jsou v jazyce C reprezentovány jako pole znaků. Jazyk C nemá žádný speciální typ pro uchování řetězce na rozdíl od Pascalu, Javy, C++ a dalších. Přesto nám jazyk C umožňuje s řetězcem normálně pracovat. Proměnnou „uchovávající” řetězec se vytvoří takto:

char jmeno[<delka>];
char jmeno[<[delka]>] = "<řetězec>";
char jmeno[<delka>] = {'a', 'h', 'o', 'j', '\0'};

První řádka vytvoří proměnnou jmeno a vyhradí prostor pro řetězce zadané délky. Ostatní uvedené postupy vyplní místo předaným řetězcem, i když první z nich je mnohem pohodlnější. Délka řetězce je nepovinný údaj při vytváření řetězce. Pokud ji vynecháme, překladač spočítá znaky v uvozovkách a vytvoří řetězec o jedna větší. Důvod, proč je řetězec větší, je to, že v jazyce C se všechny řetězce ukončují hodnotou nula (binární nula je znak '\0', neplést se znakem '0'!!). Proto se také občas řetězce v jazyce C označují jako nulou ukončené řetězce. Je jasné, že když chceme zjistit délku řetězce, musíme projít celý řetězec a počítat znaky, dokud nenarazíme na bajt s hodnotou nula (samozřejmě existuje funkce, která toto udělá za nás, viz níže). To je vcelku pomalé, zato tento způsob uchování umožňuje vytvářet libovolně dlouhé řetězce. Při vytváření řetězce nikdy nesmíme zapomínat na to, že řetězec musí být efektivně větší o jeden znak právě kvůli zarážce.

char retezec1[5] = "ahoj";
char retezec2[] = "ahoj";
char retezec3[5] = {'a', 'h', 'o', 'j', '\0'};

char retezec4[3] = "ahoj";

V ukázce výše budou první tři řetězce stejné, neboť jsme je vytvořili ekvivalentními metodami. Co ale znamená definice řetězce retezec4? Zde chceme vytvořit řetězec o délce pět, ale nutíme překladači pole velikosti tři. V tomto případě se inicializační hodnota ořízne na "aho" a řetězec nebude správně ukončen!. To tedy znamená, že když se ho pokusíme vypsat nebo s ním jinak pracovat, budeme zasahovat i do paměti, která se nachází za obsahem, a program se může chovat nedefinovaně.

Práce s řetězci

Když už umíme vytvořit řetězec, chtěli bychom ho také umět používat. V následujícím shrnutí uvádíme nejpoužívanější funkce pro práci s řetězci. Všechny se nacházejí v hlavičkovém souboru string.h.

int strcmp(const char *ret1, const char *ret2)
Tato funcke lexikograficky porovná dva řetězce. Funkce vrátí zápornou hodnotu, pokud je první řetězec lexikograficky menší, nulu, pokud jsou oba stejné, a kladnou hodnotu, je-li první řetězec lexikograficky větší.
int strncmp(const char *ret1, const char *ret2, size_t velikost)
Stejné jako strcmp() s tím rozdílem, že je vždy porovnáváno maximálně velikost znaků. Jde o bezpečnou variantu, která by měla zabránit zásahům mimo oblast řetězců. Typ size_t je typ definovaný v hlavičkovém souboru string.h jako neznaménkový celočíselný typ.
char* strcat(char *cil, const char *zdroj)
Spojí dva řetězce dohromady a výsledek uloží do proměnné cil. Volající musí zajistit, aby se výsledný řetězec do cílové proměnné vešel. Funkce vrací ukazatel na výsledný řetězec.
char* strncat(char *cil, const char *zdroj, size_t velikost)
Obdobně jako u strncmp() jde o bezpečnou variantu předchozí funkce.
size_t strlen(const char *ret)
Funkce vrátí délku řetězce ve znacích. Funkce nevrací vyhrazené místo pro řetězec, pouze počet znaků bez poslední nuly.
char* strdup(const char *s);
Funkce vrátí kopii zadaného řetězce. Pozor, takto vytvořenou kopii je později nutné uvolnit voláním funkce free() (více informací v sekci o dynamické alokaci).

Následující funkce se nacházejí v hlavičkovém souboru stdio.h.

int getchar()
Načte nejvýše jeden znak ze vstupu a uloží ho přetypovaný na int. V případě, že nastane chyba nebo že už není co načíst, vrátí funkce konstantu EOF.
void putchar(int znak)
Zapíše na výstup právě jeden znak.
char* gets(char *ret)
Načte jednu řádku do řetězce ret. Skončí, pokud narazí na konec řádky nebo na konec vstupu. V obou případech na konec přidá ukončovací nulu. Není prováděna kontrola přetečení a je na volajícím, aby vyhradil dostatečný prostor načítaný řetězec.
char* puts(const char *ret)
Zapíše do výstupu předaný řetězec bez ukončovací nuly.
int sprintf(char *ret, const char *maska, …)
Stejně jako u funkce printf() popsané v sekci proměnné a konstanty provede funkce formátovací operace a výsledek namísto standardního výstupu uloží do řetězce. Je na volajícím, aby vytvořil dostatek místa pro uložení.

Porovnávání řetězců

Řetězcové proměnné nelze porovnávat jako ostatní proměnné pomocí operátoru ==. Důvodem je, že řetězce jsou pouze převlečená pole. Pokud chceme porovnat dva řetězce, provedeme to pomocí výše uvedené funkce strcmp.

char ret[] = "ahoj";
//...
if (ret == "ahoj") // chyba!, nelze porovnávat tímto způsobem
if (strcmp(ret, "ahoj") == 0)
// nesmíme zapomínat, že jsou-li řetězce stejné, vrací funkce nulu

Procházení řetězců

Řetězce se dají procházet znak po znaku jako každé jiné pole. Pokud chceme přepsat n-tý znak v řetězci, provedeme to takto:

char ret[] = "ahoj";
ret[1] = 'c'; // v ret bude ted acoj

V jazyce C indexujeme od nuly, proto znak a by byl na pozici nula a ne jedna.