Dinamička alokacija memorije (C)
#fax #cs/prog/c [deo jezika C]
Sve funkcije su u zaglavlju <stdlib.h>
Alokacija memorije se dešava u hipu, funkcije vraćaju adresu (pokazivač), objekti nisu imenovani i nemaju doseg, imaju dinamički životni vek.
void *malloc(size_t n);
malloc
alocira blok memorije veličine n
bajtova i vraća adresu bloka (void
-pokazivač) ili NULL
ako alokacija nije uspela.
Primer alokacije niza od 100 int
-ova (sa implicitnom konverzijom tipa):
int* niz = malloc(100 * sizeof(int));
Možemo koristiti niz
isto kao obični pokazivač na 0-ti element niza (ili kao obični niz osim u dva slučaja)
void *calloc(size_t n, size_t size);
calloc
alocira blok memorije za n
objekata veličine size
i inicijalizuje ih nulama, vraća adresu bloka (void
-pokazivač) ili NULL
ako alokacija nije uspela.
int* niz = malloc(100, sizeof(int));
void *realloc(void* memblock, size_t n);
realloc
realociramemblock
u blok veličine n
i vraća adresu bloka (void
-pokazivač) ili NULL
ako alokacija nije uspela.
(Ne inicijalizuje nulama)
Ako memblock
nije pokazivač na početak bloka — greška.
realoc(NULL, k);
je isto što i malloc(k);
Posle (re)alokacije uvek bitno proveravati da li je pokazivač NULL
.
void free(void* memblock);
free
oslobađa (dealocira) memoriju kolja je bila alocirana maloc
, calloc
, realloc
.
Posle oslobođenja moramo da postavimo pokazivač na NULL
da ne bismo slučajno iskoristili.
Greške pri oslobađanju:
- oslobađanje memorije koja nije alocirana.
- oslobođenje pomoću pokazivača koji pokazuje unutar bloka, umesto na početak
- ponovo oslobađanje
Primer alokacije po unesenom broju:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, i;
scanf("%d", &n); //unos broja elemenata
//alokacija:
int* a = malloc(n*sizeof(int));
if (a == NULL) { //provera pokazivača
printf("Greska\n");
return 1;
}
for (i = 0; i < n; i++)
scanf("%d",&a[i]);
for (i = n-1; i >= 0; i--)
printf("%d ",a[i]);
free(a); //oslobađanje memorije
return 0;
}
Primer alokacije "unos do -1
":
#include <stdio.h>
#include <stdlib.h>
#define KORAK 100
int main() {
int* a = NULL; //niz je u pocetku prazan
int duzina = 0; //broj popunjenih elemenata niza
int alocirano = 0;
do {
if (duzina == alocirano) {
alocirano += KORAK;
a = realloc(a, alocirano*sizeof(int));
if (a == NULL) return 1;
}
scanf("%d", &a[duzina]);
} while (a[duzina++] != -1);
// ...
free(a);
return 0;
}
Greške
- Curenje memorije — kada se izgubi pokazivač na alocirani blok:
p = malloc(1000); ... p = malloc(2000);
- Pristup oslobođenoj memoriji
- Pristup memorije van bloka
- Oslobađanje/realokacija pogrešnog pokazivača (koji ne pokazuje na početak već alociranog bloka)
Fragmentacija memorije
Često alociranje i dealociranje može dovesti do fragmentacije.
Uprošćeni primer:
Neka je 1 - alocirana memorija, 0 - nealocirana.
0000 0000 0000 0000
____ malloc
1111 0000 0000 0000
____ __ malloc
1111 1111 1100 0000
xxxx free
0000 1111 1100 0000
__ ___ malloc
0000 1111 1111 1110
__ calloc
1100 1111 1111 1110
___x xx realloc
1100 1110 0011 1110
iako je ostalo 6 nula, nemoguće je alocirati blok od 4 jedinice.
Kako izbegavati:
- izbegavati dinamičku alokaciju
- alocirati odmah u većim blokovima
- memory pooling