Dynamická alokace paměti v jazyce C
Dynamická alokace paměti v jazyce C je v informatice souhrn funkcí používaných při programování pro dynamickou alokaci paměti, její správu a uvolňování. Správa paměti v programovacím jazyku C je prováděna programátorem ručně, nikoliv automaticky. Cílem je požádat jádro operačního systému o přidělení souvislého úseku operační paměti pro potřeby běžícího procesu nebo ji naopak operačnímu systému vrátit. Proces může paměť alokovat nebo vracet opakovaně. Po ukončení procesu je veškerá alokovaná paměť vrácena operačnímu systému k dalšímu použití.

Implementace 
Dynamická alokace paměti je v programovacím jazyce C realizována sadou funkcí ve standardní knihovně jazyka C. Jedná se o funkce malloc(), realloc(), calloc() a free().

V programovacím jazyce C++ jsou tyto funkce pouze pro zachování zpětné kompatibility s jazykem C, preferované je použití operátoru new (new a new[]).

Popis činnosti 
V jazyce C lze používat statické, automatické i dynamické přidělování (alokaci) paměti.

Staticky alokované proměnné jsou umístěny do hlavní paměti, velmi často přímo s výkonným kódem programu. Existují po celou dobu běhu programu, ať už jsou programem využity nebo ne. Automaticky alokované proměnné jsou alokovány do zásobníku a vznikají a zanikají z potřeby programu. Pro tyto proměnné platí, že velikost jejich alokace musí být v průběhu kompilování neměnná (s výjimkou C99, která umožňuje pole s variabilní délkou). Pokud potřebná velikost není známá do běhu programu (v případě čtení velikosti z disku nebo od uživatele), potom použití fixní velikosti objektu není na místě.

Statické nebo automatické alokování paměti nemusí být vhodné pro všechny situace. Data z automaticky alokované paměti nepřetrvají přes vícenásobné volání funkce (respektive funkcí), zatímco statická data přetrvávají v paměti, ať už jsou programem využita nebo nevyužita. V mnoha případech tak záleží na programátorovi a jeho umu nakládat s alokací paměti.

Těmto problémům se lze vyhnout při použití dynamicky alokované paměti. Paměť je v tomto případě řízena mnohem příměji (ale pružněji), typicky alokováním z volného místa v paměti (halda). V programovacím jazyce C je knihovní funkce malloc() používána k alokaci paměti právě v haldě. Program přistupuje k této oblasti skrz ukazatel, který mu navrátí funkce malloc(). Pokud není potřeba tuto oblast paměti dále udržovat pak je pointer předán funkci free(), která danou paměť označí jako volnou.

Použití funkce malloc() může předcházet systémovým voláním a to využitím fast bins.

Některé platformy umožňují volání knihovních funkcí, které dynamicky naalokují paměť za běhu programu v zásobníku C namísto haldy (například alloca()). Tato paměť je automaticky uvolněna když skončí funkce.

Přehled funkcí 
Funkce pro dynamické alokování paměti v jazyce C jsou definovány v knihovně stdlib.h (pro C++ cstdlib).

Rozdíly mezi funkcí calloc() a malloc() 
Jsou dva rozdíly mezi těmito funkcemi. První je v počtu argumentů. Funkce malloc() přebírá pouze jeden argument, tím je velikost paměti k alokaci. Zatímco calloc() přebírá argumenty dva, počet proměnných k alokaci a velikost jedné proměnné v bytech. Druhým rozdílem je inicializace. Funkce malloc() neinicializuje blok v paměti. Zatímco funkce calloc() inicializuje všechny byty alokované paměti na nulu.

Příklady použití 
Vytvoření pole deseti integerů je v jazyce C jednoduchá záležitost: int pole[10];

Nicméně velikost alokace paměti tohoto pole bude po kompilaci neměnná. Pokud by toto pole bylo alokováno dynamicky, pak by kód vypadal následovně:
 int * pole = malloc(10 * sizeof(int));
Toto vypočítá velikost paměti (v bytech), kterou zabere 10 integerů v paměti. Poté požádá o tento počet bytů malloc() a přiřadí výsledný ukazatel jménem pole (díky syntaxi jazyka C, ukazatele a pole mohou být zaměnitelné).

Protože malloc() nemusí být schopen obsloužit tuto žádost, může vrátit ukazatel s nulovou hodnotou a je třeba tuto událost ošetřit v kódu:

 int * pole;
 if ( NULL == (pole = malloc(10 * sizeof(int))) ) {
   printf("malloc byl chybny\n");
   return(-1);
 }

Pokud program nadále nepotřebuje toto dynamické pole, může zavolat funkci free() a uvolnit tak paměť.

 free(pole);

Paměť vyčleněná funkcí malloc() není inicializovaná a může obsahovat data z dřívějších alokací, je tedy zapotřebí danou oblast vyčistit od dřívějších dat. Naproti tomu funkce calloc() inicializuje a vyčistí oblast dat najednou. Následující příklad alokuje oblast v paměti dost velkou na to, aby se do ní vešlo 10 integerů a všechny byty nastaví hodnotou na 0.

 int * pole = calloc(10, sizeof (int));

Typová bezpečnost 
Funkce malloc() vrací obecný ukazatel (void *), který ukazuje na oblast v paměti neurčeného datového typu. Přetypování není v jazyce C vyžadováno, ale je naopak vyžadováno v silně typových jazycích jako je jazyk C++. Chybějící typ ukazatele vrácený z funkce malloc() je některými programátory považován za nebezpečné chování procesu, protože funkce malloc() alokuje paměť na základě počtu bajtů, nikoli však na základě typu. To je rozdíl proti operátoru new() v jazyce C++, kde typ ukazatele závisí na operandu.

Ukazatel může být v jazyce C přetypován na specifický typ:

 int * ukazatel;
 ukazatel = malloc(10 * sizeof(int));                 /* bez přetypování v jazyce C */
 ukazatel = (int *) malloc(10 * sizeof(int));         /* s přetypováním v jazyce C */

Přetypování v jazyce C++:
 ukazatel = reinterpret_cast <int *> (malloc(10 * sizeof(int)));      /* s přetypováním v jazyce C++ */

Přetypování má své výhody i nevýhody.

Výhody přetypování 
 Používání přetypování může umožnit program nebo funkci z jazyka C kompilovat jako program v jazyce C++
 Přetypování umožní použití starší ANSI C verze jazyka C, kde funkce malloc() vrací typ char *
 Přetypování umožňuje vývojáři identifikovat chyby v typových nesrovnalostech

Nevýhody přetypování 
 Ve standardu ANSI C je přetypování redundantní
 Použití přetypování může maskovat chybu s chybějící knihovnou stdlib.h, kde se malloc() nachází. Pokud tento prototyp malloc() chybí, standardně kompilátor považuje návratovou hodnotu z malloc() jako int. Pokud není použito přetypování kompilátor nahlásí chybu při přiřazení. Při použití přetypování se tato chyba neobjeví a zůstane skryta. Na mnohých architekturách (jako LP64 kde long a ukazatele bývají 64bitové a int je 32bitový), tato chyba může vést k destrukci zásobníku. Moderní kompilátory už tuto chybu zachytávají a je méně pravděpodobné, že by k ní došlo bez ohledu na to jestli je přetypování používáno nebo ne.

Známé problémy 
Špatné používání dynamického alokování paměti může vést k mnoha chybám. Může se jednat o problémy bezpečnostní i problémy s pády programů.

Nejčastější chyby jsou:
 Selhání alokace paměti – alokace paměti pomocí funkce malloc()může selhat a v takovémto případě je navrácen nulový ukazatel. Pokud programátor nezajistí kontrolu alokace, proces skončí kvůli chybě s nulovým ukazatelem (null pointer reference).
 Únik paměti – jedná se o problém, kdy programátor vůbec nebo nesprávně volá funkci free(). Toto plýtvání může vést k tomu, že paměť bude vyčerpána.
 Logické chyby – všechny alokace probíhají ve stejném sledu – alokace pomocí malloc(), použití paměti a uvolnění paměti funkcí free(). Velmi často dochází k chybám s dodržením tohoto postupu jako dvojité volání funkce free(), opětovné používání paměti po uvolnění funkcí free(), vedou k chybě a předčasnému ukončení procesu. Tento typ chyb je velmi těžké odhalit. Například uvolnění paměti není okamžitě obslouženo jádrem OS, a tedy již zrušené ukazatele mohou stále existovat.

Předefinování malloc() 
Protože malloc() a jeho alternativy mohou mít velký dopad na výkon programu, není neobvyklé že si programátoři tyto funkce přizpůsobí pro své aplikace. Ačkoliv jazyk C přímo toto neumožňuje, existují cesty jak tohoto dosáhnout. Například s využitím knihoven a dynamického propojování a odkazem na jinou knihovnu. V Unixu V.3 je používán ukazatel na funkce free() a malloc(), který aplikace mohou přepsat a odkázat tak na vlastní implementaci.

Limity velikosti alokace 
Největší možný blok paměti, který malloc() může alokovat závisí na operačním systému, fyzické velikosti paměti apod. Teoreticky je největší možná velikost dána implementací typu size_t, jedná se o bezznaménkové celé číslo (integer). Ve standardu C99 a následujících, je možné použít konstantu SIZE_MAX z knihovny <stdint.h>.

Rozšíření a alternativy 
Implementace knihovny jazyka C pro různé systémy, dává možnost kompilátorům nabídnout jiné možnosti a rozšíření k základnímu balíčku malloc() funkcí:
 alloca() – funkce alokuje určený počet bytů na zásobník, neexistuje žádá možnost uvolnění. Její používání není doporučeno. Standard C99 umožňuje deklarovat pole s proměnnou délkou a poskytuje lepší mechanismy pro alokování paměti na zásobníku.
 POSIX definuje funkci posix_memalign

Odkazy

Reference

Související články 
 Dynamická alokace paměti

Programovací jazyk C
Správa paměti