Knihovna stdlib.h

Standardní knihovna <stdlib.h> deklaruje spoustu užitečných funkcí. Mnohé z nich jsem již v předchozím výkladu použil. Je dobré se tyto funkce naučit používat. Například funkce qsort() slouží pro třídění datových polí. Jistě byste dokázali napsat vlastní funkci na třídění. V programu dynamic1.c jsem data třídil vlastním algoritmem. Použití funkce qsort() by však bylo rychlejší – jak z pohledu výkonu programu, tak z pohledu doby psaní programátorem. A navíc, od programátorem nově vymýšlené fukce je už tato odladěná, bezchybná…

Výčet funkcí

long int strtol(const char *nptr, char **endptr, int base);
Převede řetězec nptr na číslo vzhledem k číselné soustavě base. Adresu prvního znaku, který nepatří do čísla, uloží do endptr, pokud endptr není nastaveno na NULL.
int atoi(const char *nptr);
Převede řetězec nptr na číslo typu int. Tato funkce nedetekuje žádné chyby. Její chování je totožné s voláním strtol(nptr, (char **)NULL, 10);
Převede řetězec nptr na číslo typu double. Tato funkce nedetekuje žádné chyby.
Převede řetězec nptr na číslo typu long int. Tato funkce nedetekuje žádné chyby.
Inicializuje generátor pseudonáhodných čísel.
Vrací pseudonáhodná čísla mezi 0 a RAND_MAX
void *calloc(size_t nmemb, size_t size);
Dynamicky alokuje paměť nmemb položek velikosti size. Do alokované paměti zapíše nuly. Vrací ukazatel na alokovanou paměť nebo NULL v případě chyby.
Dynamicky alokuje paměť velikosti size. Paměť nevynuluje. Vrací ukazatel na alokovanou paměť nebo NULL v případě chyby.
void free(void *ptr);
Uvolní dynamicky alokovanou paměť (pomocí malloc(), calloc() nebo realloc()) na kterou ukazuje ptr.
void *realloc(void *ptr, size_t size);
Změní velikost dynamicky alokované paměti ptr na velikost size.
Způsobí abnormální ukončení programu. Chování funkce je implementačně závislé.
void exit(int status);
Funkce exit ukončí program kdekoliv je v programu volána. Program pak vrací operačnímu systému hodnotu status. Všechny funkce registrované funkcemi atexit() a on_exit() jsou vyvolány v opačném pořadí jejich registrace.
Přiřadí funkci do seznamu funkcí, které jsou volány při normálním ukončení programu funkcí exit() nebo skončením funkce main(). Argument function je ukazatelem na funkci bez argumentů a bez návratové hodnoty. Funkce takto registrované jsou volány v opačném pořadí než jsou registrovány. Funkce atexit() vrací 0 v případě úspěchu, -1 v případě chyby (např. nedostatek paměti pro registraci funkce).
int system (const char *string);
Volá systémový příkaz určený řetězcem string. Například tak můžete zavolat příkaz DOSu "COPY c:\soubor1.txt c:\soubor2.txt". V Linuxu se nedoporučuje používat funkci system() v programech se superuživatelskými právy. Toho by šlo totiž snadno zneužít zlými lidmi. Nepodaří-li se spustit shell (příkazový řádek), vrací funkce system() hodnotu 127, v případě jiné chyby -1. V ostatních případech vrací návratový kód příslušného příkazu.
Vyhledá hodnotu prostředí systému určenou řetězcem name. Vrátí ukazatel na tuto hodnotu, nebo NULL v případě neúspěšného hledání. Hodnoty prostředí jsou tvořeny řetězci ve formě název=hodnota. Tuto funkci budou asi využívat hlavně příznivci Linuxu, kde se jedná například o hodnoty USER, LOGNAME, HOME, PATH, SHELL, TERM apod.
int abs(int j);
Vrací absolutní hodnotu argumentu typu int.
Vrací absolutní hodnotu argumentu typu long int.
div_t div(int numer, int denom);
Počítá podíl numer/denom. Podíl a zbytek po dělení vrací ve struktuře div_t. Tato struktura obsahuje složku quot, která obsahuje podíl a složku rem, která obsahuje zbytek. Obě složky jsou celočíselné. Struktura div_t je také definována v <stdlib.h>
ldiv_t ldiv(long int numer, long int denom);
Jako funkce div(), jenom je všechno v dlouhých celých číslech.
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
Funkce qsort() třídí algoritmem quicksort souvislé pole libovolného typu (!), na které ukazuje base o nmemb položkách velikosti size. K třídění je použita funkce na kterou ukazuje compar. Funkci compar() budou při volání předávány jako argumenty prvky z pole base. Funkce compar() musí vracet zápornou hodnotu, pokud je první argument menší než druhý, nulovou hodnotu pokud se rovnají a kladnou hodnotu pokud je první argument větší než druhý.
void *bsearch(const void *key, const void *base,
                     size_t nmemb, size_t size,
                     int (*compar)(const void *, const void *));
Vyhledá prvek key v poli base dlohém nmemb položek. Položka je velikosti size a k nalezení prvku se použije porovnávací funkce compar(), která vrací 0 v případě rovnosti prvků. Pole base musí být vzestupně setříděné!

Toto není úplný výčet funkcí z knihovny <stdlib.h>. Prostudujte si vaši dokumentaci k jazyku C, chcete-li znát všechny funkce.

Užitečná makra

Kromě těchto funkcí jsou v souboru <stdlib.h> definována i některá užitečná makra. Jejich používání zvyšuje přenositelnost programu.

EXIT_FAILURE
Hodnota argumentu funkce exit() pro oznámení neúspěšného ukončení programu. (nenulová hodnota)
EXIT_SUCCESS
Hodnota argumentu funkce exit() pro úspěšné ukončení programu. (nulová hodnota)
NULL
Nulový ukazatel.
RAND_MAX
Největší hodnota generovaná funkcí rand().

Poznámky k funkcím

Vezměme to hezky popořádku. Funkci atoi() jsem již ukazoval. Je to tak jednoduché, že snad není třeba nic dodávat. Funkce rand() a srand() také již znáte. Funkce calloc(), malloc(), free() a realloc() jsou popisovány v kapitole o dynamické alokaci paměti.

Použití funkce exit() jste již viděli, ale ještě vám k ní něco povím. Víte, že funkce exit() ukončí program kdekoliv je volána. Volání funkce exit(x) je stejné, jak byste volali return x ve funkci main(). Hodnota x je vrácena do prostředí, ve kterém je program spuštěn, popřípadě procesu, který tento program spustil (ukáži v příkladě na funkci system()). Tuto hodnotu lze testovat třeba v dávkových souborech (.BAT) v DOSu nebo v unixových skriptech shellu. Není však účelem tohoto článku popisovat dávkové soubory. Stačí jen, když budete vědět, že nulová návratová hodnota se považuje za bezchybné ukončení programu a díky tomu skripty (dávkové soubory) zjišťují, zda program udělal to co měl, či ne. Návratovou hodnotou různých čísel také můžete informovat o různých příčinách konce programu. Není tedy vůbec nutné brát nenulovou hodnotu jako chybu, je to ale dobrý zvyk.

V systémech Unix je možné zjistit návratový kód naposledy spuštěného programu v systémové proměnné ?. Například příkazem echo $?.

Některé návratové hodnoty mají v různých systémech různý specifický význam. Proto, pokud nemáte zvláštní důvod činit jinak, ukončujte funkce (program) s návratovou hodnotou 0 (EXIT_SUCCESS) v případě úspěchu a 1 (EXIT_FAILURE) v případě neúspěchu.

Funkce exit() navíc před ukončením programu (stejně jako return ve funkci main()) spustí funkce registrované pomocí atexit(). Kde a jak jsou registrované, o to se nemusíte starat. Důležité je vědět, že jsou tyto registrované funkce volány vždy při skončení programu, nedojde-li k jeho ukončení funkcí abort() nebo jinému nestandardnímu konci programu.

Využít se toho dá mnoha způsoby. Například můžete vytvořit při spuštění programu nějaký dočasný soubor, který takto registrovanou funkcí smažete. Pokud se program spustí a tento soubor existuje, znamená to, že je program spuštěný vícekrát, nebo že byl nestandardně ukončen.

Funkce system() udělá zhruba to, co by udělal operační systém po zadání příkazu, který je argumentem funkce system(). Použití této funkce ukáži v příkladu, nic těžkého na tom není.

Funkci getenv() budu vysvětlovat v části věnované programování v Linuxu. Její použití je totiž silně závislé na prostředí, ve kterém je program spouštěn. Využívá se například v souvislosti s dávkovými soubory.

Co se týče funkcí div() a ldiv(), ukážu jen definici struktury div_t. Pokud umíte pracovat se strukturami, nepotřebujete znát více. Hlavně si musíte dát pozor na dělení nulou!. To by váš program zabilo!

typedef struct {
      int quot;      /* Quotient. */
      int rem;       /* Remainder. */
} div_t;

Pochopení funkce qsort() bude zřejmě nejtěžší. Funkci qsort() se ještě budu věnovat v kapitole o třídění. Tato funkce třídí prvky na základě návratové hodnoty funkce, na kterou ukazuje compar (viz ukazatele na funkce). Jelikož je tento ukazatel deklarován jako int (*compar)(const void *, const void *);, je třeba funkci, která provádí porovnávání prvků z tříděného pole přetypovat.
Řekněme, že naše třídící funkce se bude jmenovat tridici_funkce. Její návratová hodnota musí být typu int. Argumenty budou nějaké datové typy nebo struktury, ale při volání funkcí qsort() musí být tato funkce přetypována na funkci s argumenty typu void *. To se provede následujícím způsobem:

qsort(tridene_pole, POCET_PRVKU_POLE, sizeof(prvek_pole),
      (int (*) (const void *, const void *)) tridici_funkce);

Příklad použití

V prvním příkladě vytvořím pole struktury cisla obsahující typ div_t a dvě čísla, jejichž podíl a zbytek po dělení bude v právě v proměnné typu div_t.
Toto pole pak setřídím pomocí qsort(). K porovnávání prvků si vytvořím funkci s názvem srovnej_cislo().

  1. /*------------------------------------------------*/
  2. /* c22/qsort1.c                                   */
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6.  
  7. #define DELKAPOLE 20
  8.  
  9.     int x, y;
  10.     div_t podil;
  11. } cisla;
  12.  
  13. int srovnej_cislo(cisla * a, cisla * b)
  14. {
  15.     /* nejdrive tridim podle zbytku */
  16.     if (a->podil.rem > b->podil.rem)
  17.         return 1;
  18.     else if (a->podil.rem < b->podil.rem)
  19.         return -1;
  20.     /* kdyz jsou si zbytky rovny, tridim podle
  21.      * podilu */
  22.     else if (a->podil.quot > b->podil.quot)
  23.         return 1;
  24.     else if (a->podil.quot < b->podil.quot)
  25.         return -1;
  26.     else
  27.         return 0; /* jsou si rovny */
  28. }
  29.  
  30. int main(void)
  31. {
  32.     size_t i;
  33.     cisla pole[DELKAPOLE];
  34.     for (i = 0; i < DELKAPOLE; i++) {
  35.         pole[i].x = i;
  36.         pole[i].y = 5;
  37.         pole[i].podil = div(pole[i].x, pole[i].y);
  38.     }
  39.  
  40.     qsort(pole, sizeof(pole) / sizeof(pole[0]), sizeof(pole[0]),
  41.           (int (*)(const void *, const void *)) srovnej_cislo);
  42.  
  43.     for (i = 0; i < DELKAPOLE; i++) {
  44.         printf("%2i/%2i = %2i (%2i)\n", pole[i].x, pole[i].y,
  45.                pole[i].podil.quot, pole[i].podil.rem);
  46.     }
  47.  
  48.     return 0;
  49. }
  50.  
  51. /*------------------------------------------------*/

Výstup z programu:

 0/ 5 =  0 ( 0)
 5/ 5 =  1 ( 0)
10/ 5 =  2 ( 0)
15/ 5 =  3 ( 0)
 1/ 5 =  0 ( 1)
 6/ 5 =  1 ( 1)
11/ 5 =  2 ( 1)
16/ 5 =  3 ( 1)
 2/ 5 =  0 ( 2)
 7/ 5 =  1 ( 2)
12/ 5 =  2 ( 2)
17/ 5 =  3 ( 2)
 3/ 5 =  0 ( 3)
 8/ 5 =  1 ( 3)
13/ 5 =  2 ( 3)
18/ 5 =  3 ( 3)
 4/ 5 =  0 ( 4)
 9/ 5 =  1 ( 4)
14/ 5 =  2 ( 4)
19/ 5 =  3 ( 4)

V následujícím příkladě ukáži volání funkcí exit(), abort() a použití funkce atexit(). Program bude vracet hodnotu, kterou uživatel zadá z příkazové řádky.

  1. /*------------------------------------------------*/
  2. /* c22/konec.c                                    */
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6.  
  7. void koncim1(void)
  8. {
  9.     printf("Elektrina odpojena!\n");
  10. }
  11.  
  12. void koncim2(void)
  13. {
  14.     printf("Systemy vypnuty!\n");
  15. }
  16.  
  17. int main(int argc, char *argv[])
  18. {
  19.  
  20.     atexit(koncim1);
  21.     /* nejdrive probehne funkce koncim2 a pak koncim1,
  22.        tedy v obracenem poradi nez byli registrovany */
  23.     atexit(koncim2);
  24.  
  25.     if (argc != 2) {
  26.         printf("Na prikazove radce nebyla zadana navratova hodnota!\n");
  27.         abort();
  28.     }
  29.     exit(atoi(argv[1]));
  30.  
  31.     /* tato cast programu za exit nikdy neprobehne */
  32.     return 0;
  33. }
  34.  
  35. /*------------------------------------------------*/

Podívejte se, jak se chová program v systému Linux.

$ konec                            # prikaz v Linuxu - spusteni programu
Na prikazove radce nebyla zadana navratova hodnota!
Neúspěšně ukončen (SIGABRT)        # hlaseni operacniho systemu
$ echo $?                          # prikaz v Linuxu - vypis navratove hodnoty programu
134

V DOSu se místo „Neúspěšně ukončen (SIGABRT)“ ukáže „Abnormal program termination“.

Dalším možnost spuštění (v Linuxu):

$ konec 5
Systemy vypnuty!
Elektrina odpojena!
echo $?
5

Tento program (se jménem konec) využiji i v následujícím příkladě (se jménem system1). Ukáži v něm použití funkce system(), která bude program konec volat. Program konec se bude hledat ve stejném adresáři, ve kterém bude program system1 spuštěn.

Jména programů jsou v systému DOS a Windows samozřejmě zakončena příponou .exe, ale to na příkladě nic nemění.

Problém je v návratové hodnotě funkce system(). V případě neúspěšného spuštění příkazového interpretu (např. bash nebo command.com) vrátí 127, v případě neúspěchu spuštění příkazu (např. příkaz neexistuje) vrátí -1. V případě, že příkaz (zadaný funkci system() jako textový řetězec) proběhne, vrátí funkce system() jeho návratový kód. Ovšem v Linuxu je tento návratový kód pozměněn a proto se musí na něj aplikovat makro WEXITSTATUS definované v souboru <sys/wait.h>.
Proto je v příkladu použit podmíněný překlad a pro neunixové systémy je makro WEXITSTATUS definováno tak, že nic nedělá.

  1. /*------------------------------------------------*/
  2. /* c22/system1.c                                  */
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6.  
  7. #if defined unix || defined __unix__
  8. #include <sys/wait.h>
  9. #else
  10. #define WEXITSTATUS(X) X
  11. #endif
  12.  
  13. #ifdef _MSC_VER
  14.        #define KONEC "..\\Debug\\konec.exe"
  15. #else
  16.        #define KONEC "./konec"
  17. #endif
  18.  
  19. int main(void)
  20. {
  21.     int navrat;
  22.  
  23.     /* printf("Bezim zde: %s\n", getcwd()); */
  24.  
  25.     printf("Spoustim program> konec\n");
  26.     navrat = system(KONEC);
  27.     printf("Program skoncil s navratovou hodnotou %i\n\n",
  28.            WEXITSTATUS(navrat));
  29.  
  30.     printf("Spoustim program> konec 5\n");
  31.     navrat = system(KONEC " 5");
  32.     printf("Program skoncil (%i)\n\n", WEXITSTATUS(navrat));
  33.  
  34.     return 0;
  35. }
  36.  
  37. /*------------------------------------------------*/
Visual Studio

Visual Studio ukládá spustitelné soubory do podsložky Debug. Je ale možné, že budete muset trochu experimentovat, než najdete správnou cestu k programu "konec.exe". Třeba vám k tomu pomůže funkce getcwd().

Výstup z programu:

Spoustim program> konec
Na prikazove radce nebyla zadana navratova hodnota!
Neúspěšně ukončen (SIGABRT)
Program skoncil s navratovou hodnotou 134

Spoustim program> konec 5
Systemy vypnuty!
Elektrina odpojena!
Program skoncil (5)
Komentář Hlášení chyby
Created: 29.8.2003
Last updated: 22.6.2014
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..