Alocare dinamică a memoriei în C: malloc(), calloc()

⚡ Rezumat inteligent

Alocarea dinamică a memoriei în C rezervă și eliberează memorie heap în timpul execuției folosind funcțiile malloc(), calloc(), realloc() și free() din biblioteca stdlib.h, permițând programelor să dimensioneze flexibil tablourile și structurile atunci când cerințele sunt necunoscute înainte de execuție.

  • 🧠 Stivă vs. heap: Variabilele de bază utilizează stiva automată, în timp ce memoria dinamică se află pe heap și este gestionată manual prin intermediul pointerilor.
  • 📦 malloc(): Rezervă un bloc neinițializat de dimensiunea solicitată în octeți și returnează un pointer void sau NULL atunci când memoria este insuficientă.
  • 🔢 calloc(): Alocă mai multe blocuri pentru matrici, setează fiecare octet la zero și returnează un pointer către primul bloc.
  • 🔄 realloc(): Redimensionează un bloc existent în sus sau în jos, păstrând conținutul original într-o locație posibil nouă.
  • 🧹 gratuit(): Returnează memoria către heap; fiecare malloc() sau calloc() necesită o funcție free() corespondentă pentru a preveni scurgerile de date.
  • 🤖 Ajutor AI: Asistenții AI și GitHub Copilot elaborează codul de alocare și semnalează apelurile free() lipsă și scurgerile de informații.

Alocarea dinamică a memoriei în C

Cum funcționează gestionarea memoriei în C?

Când declarați o variabilă folosind un tip de date de bază, compilatorul C alocă automat spațiu de memorie pentru variabilă într-un pool de memorie numit stivă.

De exemplu, o variabilă cu număr de tip float are de obicei 4 octeți (în funcție de platformă) atunci când este declarată. Putem verifica aceste informații folosind operatorul sizeof, așa cum se arată în exemplul de mai jos.

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

Ieșirea va fi:

 The size of float is 4 bytes

De asemenea, o matrice cu o dimensiune specificată este alocată în blocuri adiacente de memorie, fiecare bloc având dimensiunea pentru un element:

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

Rezultatul este:

 The size of the float array with 10 element is 40

După cum am învățat până acum, atunci când se declară un tip de date de bază sau o matrice, memoria este gestionată automat. Cu toate acestea, există un proces de alocare a memoriei în C care vă va permite să implementați un program în care dimensiunea matricei este nedeterminată până când rulați programul (în timpul execuției). Acest proces se numește „Alocare dinamică a memoriei”.

Alocarea dinamică a memoriei în C

Alocarea dinamică a memoriei este alocarea și eliberarea manuală a memoriei în funcție de nevoile dvs. de programare. Memoria dinamică este gestionată și servită cu pointeri care indică spațiul de memorie nou alocat într-o zonă pe care o numim heap.

Acum puteți crea și distruge o serie de elemente în mod dinamic în timpul execuției, fără probleme. Pentru a rezuma, gestionarea automată a memoriei folosește stiva, iar C Dynamic Memory Allocation folosește heap-ul.

The biblioteca are funcții responsabile pentru gestionarea dinamică a memoriei.

Funcţie Scop
malloc () Alocă memoria de dimensiunea cerută și returnează pointerul la primul octet al
spatiu alocat.
calloc() Alocă spațiu pentru elementele unui tablou. Inițializează elementele la zero și returnează un pointer în memorie.
realloc() Este folosit pentru a modifica dimensiunea spațiului de memorie alocat anterior.
Gratuit() Eliberează sau golește spațiul de memorie alocat anterior.

Să discutăm despre funcțiile de mai sus cu aplicația lor

funcția malloc() în C

Funcția C malloc() reprezintă alocare de memorie. Este o funcție care este utilizată pentru a aloca dinamic un bloc de memorie. Rezervă spațiu de memorie de dimensiunea specificată și returnează pointerul nul care indică locația de memorie. Indicatorul returnat este de obicei de tip void. Înseamnă că putem atribui funcția C malloc() oricărui pointer.

Sintaxa funcției malloc():

ptr = (cast_type *) malloc (byte_size);

Aici,

  • ptr este un pointer de tip_cast.
  • Funcția C malloc() returnează un pointer către memoria alocată pentru byte_size.

Exemplu de malloc():

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

Când această instrucțiune este executată cu succes, un spațiu de memorie de 50 de octeți este rezervat. Adresa primului octet al spațiului rezervat este atribuită pointerului ptr de tip int.

Luați în considerare un alt exemplu:

#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));
    }
}

ieșire:

Value of the 6th integer is 480

C malloc() Funcția

  1. Observați că s-a folosit sizeof(*ptr) în loc de sizeof(int) pentru a face codul mai robust atunci când declarația *ptr este convertită ulterior la un tip de date diferit.
  2. Alocarea poate eșua dacă memoria nu este suficientă. În acest caz, returnează un pointer NULL. Deci, ar trebui să includeți cod pentru a verifica dacă există un pointer NULL.
  3. Rețineți că memoria alocată este adiacentă și poate fi tratată ca o matrice. Putem folosi aritmetica pointerului pentru a accesa elementele matricei în loc să folosim paranteze [ ]. Vă sfătuim să folosiți + pentru a face referire la elementele matricei, deoarece utilizarea incrementarii ++ sau += modifică adresa stocată de indicatorul.

Funcția Malloc() poate fi utilizată și cu tipul de date caracter, precum și cu tipuri de date complexe, cum ar fi structurile.

funcția free() în C

Memoria pentru variabile este dealocat automat în timpul compilării. În alocarea dinamică a memoriei, trebuie să dealocați memoria în mod explicit. Dacă nu este făcut, este posibil să întâmpinați o eroare de memorie lipsită.

Funcția free() este apelată pentru a elibera/dealoca memorie în C. Prin eliberarea memoriei în program, faci mai multă memorie disponibilă pentru utilizare ulterioară.

De exemplu:

#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);
}

ieșire:

 Value of the 2nd integer is 50

funcția calloc() în C

Funcția C calloc() reprezintă alocare contiguă. Această funcție este utilizată pentru a aloca mai multe blocuri de memorie. Este o funcție de alocare dinamică a memoriei care este utilizată pentru a aloca memoria unor structuri complexe de date, cum ar fi matrice și structuri.

Funcția Malloc() este folosită pentru a aloca un singur bloc de spațiu de memorie, în timp ce calloc() din C este folosită pentru a aloca mai multe blocuri de spațiu de memorie. Fiecare bloc alocat de funcția calloc() este de aceeași dimensiune.

Sintaxa funcției calloc():

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

Declarația de mai sus este folosită pentru a aloca n blocuri de memorie de aceeași dimensiune.

După ce spațiul de memorie este alocat, toți octeții sunt inițializați la zero.

Este returnat indicatorul care se află în prezent la primul octet al spațiului de memorie alocat.

Ori de câte ori există o eroare la alocarea spațiului de memorie, cum ar fi deficitul de memorie, atunci este returnat un pointer nul.

Exemplu de calloc():

Programul de mai jos calculează suma unei secvențe aritmetice.

#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;
    }

Rezultat:

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

calloc() vs. malloc(): Diferențele cheie

În continuare este diferența cheie între malloc() vs calloc() în C:

Funcția calloc() este în general mai potrivită și mai eficientă decât cea a funcției malloc(). În timp ce ambele funcții sunt folosite pentru a aloca spațiu de memorie, calloc() poate aloca mai multe blocuri în același timp. Nu trebuie să solicitați un bloc de memorie de fiecare dată. Funcția calloc() este utilizată în structurile de date complexe care necesită spațiu de memorie mai mare.

Blocul de memorie alocat de un calloc() în C este întotdeauna inițializat la zero, în timp ce în funcția malloc() în C, acesta conține întotdeauna o valoare de gunoi.

funcția realloc() în C

Folosind funcția realloc() din C, puteți adăuga mai multă memorie la memoria deja alocată. Aceasta extinde blocul curent, păstrând conținutul original așa cum este. realloc() în C reprezintă realocarea memoriei.

realloc() poate fi folosit și pentru a reduce dimensiunea memoriei alocate anterior.

Sintaxa funcției realloc():

ptr = realloc (ptr,newsize);

Declarația de mai sus alocă un spațiu de memorie nou cu o dimensiune specificată în variabila newsize. După executarea funcției, indicatorul va fi returnat la primul octet al blocului de memorie. Noua dimensiune poate fi mai mare sau mai mică decât memoria anterioară. Nu putem fi siguri că dacă blocul nou alocat va indica aceeași locație cu cea a blocului de memorie anterior. Această funcție va copia toate datele anterioare în noua regiune. Se asigură că datele vor rămâne în siguranță.

Exemplu de 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;
}

Ori de câte ori realloc() în C are ca rezultat o operație nereușită, returnează un pointer nul, iar datele anterioare sunt, de asemenea, eliberate.

Matrice dinamice în C

O matrice dinamică în C permite numărului de elemente să crească după cum este necesar. C Matricele dinamice sunt utilizate pe scară largă în algoritmii informaticii.

În programul următor, am creat și redimensionat o matrice dinamică în 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);
    }

Rezultatul programului C Dynamic matrice pe ecran:

 
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

Întrebări frecvente

O scurgere de memorie apare atunci când memoria heap preluată de malloc() sau calloc() nu este niciodată eliberată. Preveniți acest lucru prin asocierea fiecărei alocări cu un apel free() corespunzător, odată ce blocul nu mai este necesar.

Un pointer suspendat păstrează în continuare adresa memoriei pe care free() a eliberat-o deja. Dereferențierea acestuia provoacă un comportament nedefinit, așadar atribuiți NULL pointerului imediat după eliberare, pentru a rămâne în siguranță.

Nu. C nu are un colector de gunoi, deci memoria heap nu este niciodată recuperată automat. Programatorul trebuie să elibereze fiecare bloc explicit cu free(); altfel, alocarea persistă până la terminarea programului.

Nu. Apelarea de două ori a metodei free() la aceeași adresă este un double free și declanșează un comportament nedefinit sau blocări. Setarea pointerului la NULL după prima metodă free() face ca orice metodă free() ulterioară să fie inofensivă.

realloc(NULL, size) acționează exact ca malloc(size) și alocă un bloc nou. realloc(ptr, 0) eliberează blocul, deci capturează întotdeauna pointerul returnat în loc să îl suprascrie pe cel original.

Instrumente precum Valgrind, AddressSanitizer și Dr. Memory track fiecare alocare și raportează blocurile care nu au fost niciodată eliberate, împreună cu linia exactă, helping Localizezi scurgerile înainte de deversare.

Da. Un asistent de codare cu inteligență artificială creează secvențe malloc(), calloc() și free() dintr-un prompt, explică erorile pointerului și semnalează apelurile free() lipsă. Compilează și testează întotdeauna codul generat înainte de a-l considera de încredere.

Copilotul GitHub sugerează blocuri de alocare, verificări NULL și apeluri free() potrivite dintr-un comentariu; verificați fiecare finalizare pentru scurgeri și dimensiuni corecte înainte de a o livra.

Rezumați această postare cu: