Dynamická alokace paměti v jazyce C: malloc(), calloc()

⚡ Chytré shrnutí

Dynamická alokace paměti v jazyce C rezervuje a uvolňuje paměť haldy za běhu pomocí funkcí malloc(), calloc(), realloc() a free() z knihovny stdlib.h, což umožňuje programům flexibilně upravovat velikost polí a struktur, pokud jsou požadavky před spuštěním neznámé.

  • 🧠 Zásobník vs. halda: Základní proměnné používají automatický zásobník, zatímco dynamická paměť se nachází na haldě a je spravována ručně pomocí ukazatelů.
  • ???? malloc(): Rezervuje jeden neinicializovaný blok požadované velikosti bajtů a vrátí ukazatel typu void nebo NULL, pokud není dostatek paměti.
  • 🔢 calloc(): Alokuje více bloků pro pole, nastaví každý bajt na nulu a vrátí ukazatel na první blok.
  • 🔄 realoc(): Změní velikost existujícího bloku nahoru nebo dolů a zároveň zachová původní obsah na případně novém místě.
  • 🧹 volný, uvolnit(): Vrací paměť do haldy; každá funkce malloc() nebo calloc() potřebuje odpovídající funkci free(), aby se zabránilo únikům.
  • 🤖 Pomoc s umělou inteligencí: Asistenti umělé inteligence a GitHub Copilot navrhují alokační kód a označují chybějící volání free() a úniky.

Dynamická alokace paměti v C

Jak funguje správa paměti v C?

Když deklarujete proměnnou pomocí základního datového typu, kompilátor jazyka C automaticky alokuje paměťový prostor pro tuto proměnnou v paměťovém fondu nazývaném zásobník.

Například proměnná s plovoucí čárkou (float) při deklaraci obvykle zabírá 4 bajty (v závislosti na platformě). Tuto informaci můžeme ověřit pomocí operátoru sizeof, jak je znázorněno v níže uvedeném příkladu.

#include <stdio.h>
int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0;}

Výstup bude:

 The size of float is 4 bytes

Také pole se zadanou velikostí je alokováno v souvislých blocích paměti, každý blok má velikost pro jeden prvek:

#include <stdio.h>
int main() { float arr[10];
printf("The size of the float array with 10 element is %d", sizeof(arr)); return 0;}

Výsledek je:

 The size of the float array with 10 element is 40

Jak jsme se dosud dozvěděli, při deklaraci základního datového typu nebo pole je paměť spravována automaticky. Existuje však proces pro alokaci paměti v jazyce C, který umožňuje implementovat program, ve kterém je velikost pole neurčitá, dokud program nespustíte (běhové prostředí). Tento proces se nazývá „dynamická alokace paměti“.

Dynamická alokace paměti v C

Dynamická alokace paměti je ruční alokace a uvolňování paměti podle vašich programátorských potřeb. Dynamická paměť je spravována a obsluhována pomocí ukazatelů, které odkazují na nově alokovaný paměťový prostor v oblasti, kterou nazýváme halda.

Nyní můžete bez problémů dynamicky vytvářet a ničit pole prvků za běhu. Abych to shrnul, automatická správa paměti používá zásobník a dynamická alokace paměti C používá haldu.

The knihovna má funkce zodpovědné za dynamickou správu paměti.

funkce Účel
malloc () Přidělí paměť požadované velikosti a vrátí ukazatel na první bajt
přidělený prostor.
calloc() Přiděluje prostor pro prvky pole. Inicializuje prvky na nulu a vrátí ukazatel do paměti.
realloc() Používá se k úpravě velikosti dříve přiděleného paměťového prostoru.
Volný, uvolnit() Uvolní nebo vyprázdní dříve přidělený paměťový prostor.

Pojďme si probrat výše uvedené funkce s jejich aplikací

funkce malloc() v C

Funkce C malloc() znamená alokaci paměti. Je to funkce, která se používá k dynamickému přidělování bloku paměti. Vyhradí paměťový prostor zadané velikosti a vrátí nulový ukazatel ukazující na místo v paměti. Vrácený ukazatel je obvykle typu void. To znamená, že funkci C malloc() můžeme přiřadit libovolnému ukazateli.

Syntaxe funkce malloc():

ptr = (cast_type *) malloc (byte_size);

Zde,

  • ptr je ukazatel cast_type.
  • Funkce C malloc() vrací ukazatel na přidělenou paměť velikosti byte_size.

Příklad malloc():

Example: ptr = (int *) malloc (50)

Po úspěšném provedení tohoto příkazu je rezervován paměťový prostor o velikosti 50 bajtů. Adresa prvního bajtu rezervovaného prostoru je přiřazena ukazateli ptr typu int.

Zvažte další příklad:

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

Výstup:

Value of the 6th integer is 480

C funkce malloc().

  1. Všimněte si, že místo sizeof(int) bylo použito sizeof(*ptr), aby byl kód robustnější při pozdější přetypování deklarace *ptr na jiný datový typ.
  2. Alokace může selhat, pokud paměť není dostatečná. V tomto případě vrátí ukazatel NULL. Měli byste tedy zahrnout kód pro kontrolu ukazatele NULL.
  3. Mějte na paměti, že přidělená paměť je souvislá a lze s ní zacházet jako s polem. Pro přístup k prvkům pole můžeme použít aritmetiku ukazatele namísto použití závorek [ ]. Doporučujeme používat + k odkazování na prvky pole, protože použití inkrementace ++ nebo += změní adresu uloženou v ukazatel.

Funkci Malloc() lze také použít se znakovým datovým typem a také s komplexními datovými typy, jako jsou struktury.

funkce free() v C

Paměť pro proměnné je automaticky uvolněna v době kompilace. Při dynamické alokaci paměti musíte explicitně uvolnit paměť. Pokud tak neučiníte, může dojít k chybě nedostatku paměti.

Funkce free() se v jazyce C volá pro uvolnění/dealokaci paměti. Uvolněním paměti v programu zpřístupníte více paměti pro pozdější použití.

Například:

#include <stdio.h>
int main() {
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL){
  *(ptr + 2) = 50;
  printf("Value of the 2nd integer is %d",*(ptr + 2));
}
free(ptr);
}

Výstup:

 Value of the 2nd integer is 50

funkce calloc() v C

Funkce C calloc() znamená souvislou alokaci. Tato funkce se používá k přidělení více bloků paměti. Je to funkce dynamického přidělování paměti, která se používá k přidělování paměti složitým datovým strukturám, jako jsou pole a struktury.

Funkce Malloc() se používá k přidělení jednoho bloku paměti, zatímco calloc() v C se používá k přidělení více bloků paměti. Každý blok přidělený funkcí calloc() má stejnou velikost.

Syntaxe funkce calloc():

ptr = (cast_type *) calloc (n, size);

Výše uvedený příkaz se používá k alokaci n paměťových bloků stejné velikosti.

Po přidělení paměťového prostoru jsou všechny bajty inicializovány na nulu.

Je vrácen ukazatel, který je aktuálně na prvním bajtu přiděleného paměťového prostoru.

Kdykoli dojde k chybě při přidělování místa v paměti, jako je nedostatek paměti, vrátí se ukazatel null.

Příklad calloc():

Níže uvedený program vypočítá součet aritmetické posloupnosti.

#include <stdio.h>
    int main() {
        int i, * ptr, sum = 0;
        ptr = calloc(10, sizeof(int));
        if (ptr == NULL) {
            printf("Error! memory not allocated.");
            exit(0);
        }
        printf("Building and calculating the sequence sum of the first 10 terms \ n ");
        for (i = 0; i < 10; ++i) { * (ptr + i) = i;
            sum += * (ptr + i);
        }
        printf("Sum = %d", sum);
        free(ptr);
        return 0;
    }

Výsledek:

Building and calculating the sequence sum of the first 10 terms
Sum = 45

calloc() vs. malloc(): Klíčové rozdíly

Následuje klíčový rozdíl mezi malloc() versus calloc() v C:

Funkce calloc() je obecně vhodnější a efektivnější než funkce malloc(). Zatímco obě funkce se používají k alokaci paměťového prostoru, calloc() může alokovat více bloků najednou. Nemusíte pokaždé žádat o blok paměti. Funkce calloc() se používá ve složitých datových strukturách, které vyžadují větší paměťový prostor.

Paměťový blok přidělený calloc() v C je vždy inicializován na nulu, zatímco ve funkci malloc() v C vždy obsahuje nesmyslnou hodnotu.

funkce realloc() v C

Pomocí funkce realloc() v jazyce C můžete přidat další paměť k již alokované paměti. Tato funkce rozšíří aktuální blok a zároveň ponechá původní obsah beze změny. realloc() v jazyce C znamená realokaci paměti.

realloc() lze také použít ke zmenšení velikosti dříve přidělené paměti.

Syntaxe funkce realloc():

ptr = realloc (ptr,newsize);

Výše uvedený příkaz alokuje nový paměťový prostor se zadanou velikostí v proměnné newsize. Po provedení funkce se ukazatel vrátí na první bajt paměťového bloku. Nová velikost může být větší nebo menší než předchozí paměť. Nemůžeme si být jisti, že pokud nově přidělený blok bude ukazovat na stejné místo jako předchozí paměťový blok. Tato funkce zkopíruje všechna předchozí data v nové oblasti. Zajišťuje, že data zůstanou v bezpečí.

Příklad realloc():

#include <stdio.h>
int main () {
   char *ptr;
   ptr = (char *) malloc(10);
   strcpy(ptr, "Programming");
   printf(" %s,  Address = %u\n", ptr, ptr);

   ptr = (char *) realloc(ptr, 20); //ptr is reallocated with new size
   strcat(ptr, " In 'C'");
   printf(" %s,  Address = %u\n", ptr, ptr);
   free(ptr);
   return 0;
}

Kdykoli způsobí realloc() v C neúspěšnou operaci, vrátí ukazatel null a předchozí data se také uvolní.

Dynamická pole v C

Dynamické pole v C umožňuje růst počtu prvků podle potřeby. C Dynamické pole jsou široce používány v algoritmech počítačové vědy.

V následujícím programu jsme vytvořili a změnili velikost dynamického pole C

#include <stdio.h>
    int main() {
        int * arr_dynamic = NULL;
        int elements = 2, i;
        arr_dynamic = calloc(elements, sizeof(int)); //Array with 2 integer blocks
        for (i = 0; i < elements; i++) arr_dynamic[i] = i;
        for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
        elements = 4;
        arr_dynamic = realloc(arr_dynamic, elements * sizeof(int)); //reallocate 4 elements
        printf("After realloc\n");
        for (i = 2; i < elements; i++) arr_dynamic[i] = i;
        for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
        free(arr_dynamic);
    }

Výsledek programu C Dynamic array na obrazovce:

 
arr_dynamic[0]=0
arr_dynamic[1]=1
After realloc
arr_dynamic[0]=0
arr_dynamic[1]=1
arr_dynamic[2]=2
arr_dynamic[3]=3

Nejčastější dotazy

K úniku paměti dochází, když paměť haldy obsazená funkcí malloc() nebo calloc() není nikdy uvolněna. Tomu předejdete tak, že každou alokaci spárujete s odpovídajícím voláním free(), jakmile blok již není potřeba.

Volný ukazatel stále obsahuje adresu paměti, kterou již uvolnila funkce free(). Jeho dereferencování způsobí nedefinované chování, proto pro jistotu ihned po uvolnění ukazatele přiřaďte hodnotu NULL.

Ne. C nemá garbage collector, takže paměť haldy se nikdy automaticky neuvolňuje. Programátor musí každý blok explicitně uvolnit pomocí free(); jinak alokace přetrvává, dokud se program neukončí.

Ne. Dvojité volání free() na jedné adrese je dvojité volání a spouští nedefinované chování nebo pád. Nastavení ukazatele na NULL po prvním free() zneškodní jakékoli další free().

Funkce realloc(NULL, size) se chová přesně jako malloc(size) a alokuje nový blok. Funkce realloc(ptr, 0) blok uvolní, takže vždy zachytí vrácený ukazatel, místo aby přepsal původní.

Nástroje jako Valgrind, AddressSanitizer a Dr. Memory track každou alokaci a nahlásit bloky, které nikdy nebyly uvolněny, spolu s přesným řádkem helping před uvolněním zjistíte netěsnosti.

Ano. Asistent kódování s umělou inteligencí navrhuje sekvence malloc(), calloc() a free() z promptu, vysvětluje chyby ukazatelů a signalizuje chybějící volání free(). Vždy zkompilujte a otestujte vygenerovaný kód, než mu budete důvěřovat.

GitHub Copilot navrhuje alokační bloky, kontroly NULL a odpovídající volání free() z komentáře; před odesláním zkontrolujte každé dokončení, zda neobsahuje úniky a správné velikosti.

Shrňte tento příspěvek takto: