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);
freeoslobađ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
