Warning
This page is located in archive.

Dynamická alokace paměti v C

Při programovaní pracujeme s děma typy paměti, statickou a dynamickou. Přidělení statické paměti řeší kompilátor a není nutné se o něj nijak starat. Nevýhodou takto přidělené paměti je poměrne nízká flexibilita. Jinými slovy veškeré paměťové nároky na statickou paměť musejí být známy již v čase překladu (před samotným během programu).
Pokud ale nevíme určit jak veliká budou data s nimiž bude náš program pracovat začíná být použití statické paměti obtížné nebo minimálně nehospodárné, když alokujeme vždy paměť pro nejhorší(největší) možný případ.

Mnohem elegantnejší je použití dynamické alokace paměti (tam kde si to situace vyžaduje), která umožnuje alokovat místo v paměti přímo za běhu programu.

Správu dynamické paměti řeší tzv. run-time fukce, které pracují s pamětí za běhu programu. Ve skutečnosti se jedná o relativne složité operace silně závislé na architektuře a operačním systému. Programovací jazyk je ale zaobaluje do jednoduchých a univerzálních funkcí.

Alokace paměti - malloc, calloc

void *malloc(size_t bytes);
void *calloc(size_t n, size_t bytes);

  • Malloc() je základní funkcí pro práci s dynamickou pamětí.
  • Má jediný parametr typu size_t, který udává počet bajtů paměti, které chceme od operačního systému získat.
  • Datový typ size_t je definován v <stdlib.h>. Představuje celočíselný typ podobný unsigned int, který je dostatečně velký na adresování celé paměti.
  • Funkce vrací pointer na void*, který ukazuje tam kde začíná nově alokovaný blok, tj. ukazuje na první prvek bloku (je vhodné jej ihned přetypovat na pointer na odpovídající typ).
  • Nastanou-li nějaké potíže, např. s nedostatkem paměti, vrátí funkce malloc() (i calloc()) pointer NULL. Toto je vhodný způsob jak testovat zda proběhla alokace úspěšne.


  • Calloc() je podobná funkci malloc(), ale navíc vyplní alokovanou pamět nulami.
  • Alokuje paměť pro n položek velikosti bytes.
  • Nejčastěji se používá pro vytvoření dynamického pole struktur.

#include<stdlib.h>
 
int *ui;
/* vytvoreni dynamicke promenne */
if ((ui = (int *) malloc(sizeof(*ui))) == NULL) { /* zadost o prideleni pameti velikost typu int */
        printf("Nedostatek pameti.\n"); 
        return 1; /* případně pro ukonceni programu exit(1); */
}

Dynamicky vytvořené proměnné jednoduchých typů obvykle nejsou třeba. Užitečné je dynamicky vytvořené pole:

#include<stdlib.h>
 
int n, *up;
 
printf("Zadejte velikost pole: \n");
int r = scanf("%d", &n);
if (r != 1 || (r == 1 && n < 0)) {
    fprintf(stderr, "Nepodarilo se nacist velikost pole.\n");
    return 1; /* případně pro ukonceni programu exit(1); */
}
 
/* dynamicka alokace pameti pro jednorozmerne pole */
if ((up = (int *) malloc(n * sizeof (*up))) == NULL) { /* zadost o prideleni pameti */
    fprintf(stderr, "Nedostatek pameti.\n");
    return 1; /* případně pro ukonceni programu exit(1); */
}

Dealokace paměti - free

void free(void *aptr);

  • Funkce free() uvolní dříve přidelenou alokovanou paměť.
  • Jejím parametrem je pointer na typ void.
  • Je dobré vědět, že funkce free() sice paměť uvolní, ale nezmění hodnotu svého parametru. Pointer tak nadále bude ukazovat do již uvolněného pamětového prostoru. Proto je po každém použití free() vhodné pointer nastavit na NULL.

#include<stdlib.h>
/* uvolneni pameti vyse alokovaneho prostoru pro jednorozmerne pole */
free(up);
up = NULL;

Realokace paměti - realloc

void *realloc(void *aptr, size_t bytes);

  • Realloc() slouží ke změně velikosti dynamicky získané paměti.
  • První parametr funkce je adresa paměti, která byla alokována pomocí funkcí malloc(), calloc() nebo realloc().
  • Druhým parametr udává na jakou velikost se dříve akovaná paměť změní (zvětší/zmenší).
  • Návratovou hodnotou je ukazatel na nově alokovanou paměť. Ten ovšem nemusí ukazovat na stejné místo v paměti jako dříve!
  • Původní část paměti, která byla přealokována, zůstává zachována. Přialokovaný blok paměti má nedefinované hodnoty.
  • Nastanou-li nějaké potíže, např. s nedostatkem paměti, vrátí funkce realloc() pointer NULL. Toto je vhodný způsob jak testovat zda proběhla realokace úspěšne.

#include<stdlib.h>
 
int n, *up, *unovep;
 
printf("Zadejte velikost pole: \n");
int r = scanf("%d", &n);
if (r != 1 || (r == 1 && n < 0)) {
    fprintf(stderr, "Nepodarilo se nacist velikost pole.\n");
    return 1; /* případně pro ukonceni programu exit(1); */
}
 
/* dynamicka alokace pameti pro jednorozmerne pole */
if ((up = (int *) malloc(n * sizeof (*up))) == NULL) { /* zadost o prideleni pameti */
    printf("Nedostatek pameti.\n");
    return 1; /* případně pro ukonceni programu exit(1); */
}
 
printf("Zadejte novou velikost pole: \n");
scanf("%d", &n);
 
/* realokace vyse alokovane pameti */
if ((unovep = (int *) realloc(up, n * sizeof (*unovep))) == NULL) {
    printf("Nedostatek pameti.\n");
    return 1; /* případně pro ukonceni programu exit(1); */
}

Proč by byla chyba použít níže uvedenou konstrukci?

((up = (int *) realloc(up, n * sizeof (*up))) == NULL)

courses/b3b36prg/tutorials/coding/c_dyn_mem.txt · Last modified: 2022/02/17 11:38 by faiglj