Sunteți pe pagina 1din 65

Curs:

alocarea dinamică
laura.vasilescu@cs.pub.ro
Reminder Stivă (stack) vs Heap
Reminder Stivă (stack) vs Heap
Reminder Stivă (stack) vs Heap
• Variabile locale
Reminder Stivă (stack) vs Heap
• Variabile locale

• Variabile alocate
dinamic
Reminder Stivă (stack) vs Heap
• Variabile locale

• Variabile alocate
dinamic

• Variabile globale
Alocarea memoriei pe stivă

- recapitulare -
Exemplu didactic: procesor pe 4 biți
24-1

0
Exemplu didactic: procesor pe 4 biți
24-1

- Presupunem că, în cazul


acesta, o celulă din
memorie are și ea tot 4
biți

- Presupunem că tipul de
date halfbyte are și el 4
biți și e singurul care
există
0
Exemplu didactic: procesor pe 4 biți
0xF 14
0xE 8 Alocarea
0xD 14 variabilelor
0xC 4
0xB 11
0xA 5
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8; Alocarea
0xE 8
0xD 14 variabilelor
0xC 4
0xB 11
0xA 5
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Alocarea
0xE c = 5
0xD 14 variabilelor
0xC 4
0xB 11
0xA 5
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Alocarea
0xE c = 5
halfbyte *b, *d;
0xD b, 14 variabilelor
0xC d, 4
0xB 11 Ce valori au variabilele b și d?
0xA 5
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Alocarea
0xE c = 5
halfbyte *b, *d;
0xD b = 14 variabilelor
0xC d = 4
0xB 11
0xA 5
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Alocarea
0xE c = 5
halfbyte *b, *d;
0xD b = 14 variabilelor
0xC d = 4
0xB 11 print(b) = ?
0xA 5 print(d) = ?
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Alocarea
0xE c = 5
halfbyte *b, *d;
0xD b = 14 variabilelor
0xC d = 4
0xB 11 print(b) = 14 ; 0xE
0xA 5 print(d) = 4; 0x4
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Alocarea
0xE c = 5
halfbyte *b, *d;
0xD b = 14 variabilelor
0xC d = 4
0xB 11 print(b) = 0xE
0xA 5 print(d) = 0x4
0x9 0
0x8 3
print(*b) = ?
0x7 13
0x6 5
print(*d) = ?
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Alocarea
0xE c = 5
halfbyte *b, *d;
0xD b = 14 variabilelor
0xC d = 4
0xB 11 print(b) = 0xE
0xA 5 print(d) = 0x4
0x9 0
0x8 3
print(*b) = valoarea de la 14 = *0xE = 5
0x7 13
0x6 5
print(*d) = ?
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Alocarea
0xE c = 5
halfbyte *b, *d;
0xD b = 14 variabilelor
0xC d = 4
0xB 11 print(b) = 0xE
0xA 5 print(d) = 0x4
0x9 0
0x8 3
print(*b) = valoarea de la 14 = *0xE = 5
0x7 13
0x6 5
print(*d) = valoarea de la 4 = *0x4 =>
0x5 12 Segmentation Fault
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Modificarea
0xE c = 5
halfbyte *b, *d;
0xD b = 14 variabilelor
0xC d = 4
0xB 11 print(b) = 0xE
0xA 5 print(d) = 0x4
0x9 0
0x8 3
print(*b) = valoarea de la 14 = *0xE = 5
0x7 13
0x6 5
print(*d) = valoarea de la 4 = *0x4 =>
0x5 12 Segmentation Fault
0x4 0
0x3 4 *b = 10; ??
0x2 7 *d = 10; ??
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Modificarea
0xE c = 10
halfbyte *b, *d;
0xD b = 14 variabilelor
0xC d = 4
0xB 11 print(b) = 0xE
0xA 5 print(d) = 0x4
0x9 0
0x8 3
print(*b) = valoarea de la 14 = *0xE = 5
0x7 13
0x6 5
print(*d) = valoarea de la 4 = *0x4 =>
0x5 12 Segmentation Fault
0x4 0
0x3 4 *b = 10; se modifică valoarea de la 0xE
0x2 7 *d = 10; Segmentation Fault
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Modificarea
0xE c = 10
halfbyte *b, *d;
0xD b = 15 variabilelor
0xC d = 4
0xB 11 b = &a; adică b devine 0xF, adică 15
0xA 5
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Modificarea
0xE c = 10
halfbyte *b, *d;
0xD b = 15 variabilelor
0xC d = 14
0xB 11 b = &a;
0xA 5 d = &c; adică d devine 0xE, adică 14
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
halfbyte a = 8, c = 5; Modificarea
0xE c = 10
halfbyte *b, *d;
0xD b = 15 variabilelor
0xC d = 14
0xB 11 b = &a;
0xA 5 d = &c; adică d devine 0xE, adică 14
0x9 0
0x8 3
*b = 1; deci a devine 1
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 1
halfbyte a = 8, c = 5; Modificarea
0xE c = 10
halfbyte *b, *d;
0xD b = 15 variabilelor
0xC d = 14
0xB 11 b = &a;
0xA 5 d = &c; adică d devine 0xE, adică 14
0x9 0
0x8 3
*b = 1; deci a devine 1
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 1
halfbyte a = 8, c = 5; Modificarea
0xE c = 10
halfbyte *b, *d;
0xD b = 15 variabilelor
0xC d = 14
0xB 11 b = &a;
0xA 5 d = &c; adică d devine 0xE, adică 14
0x9 0
0x8 3
*b = 1;
0x7 13
0x6 5
d[0] = 2; deci *(0xE +0) = 2
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 1
halfbyte a = 8, c = 5; Modificarea
0xE c = 2
halfbyte *b, *d;
0xD b = 15 variabilelor
0xC d = 14
0xB 11 b = &a;
0xA 5 d = &c; adică d devine 0xE, adică 14
0x9 0
0x8 3
*b = 1;
0x7 13
0x6 5
d[0] = 2; deci *(0xE +0) = 2
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 5
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 5
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 5
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a); afișează valoarea 8
0x8 3
0x7 13
0x6 5
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 5
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
print(a);
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 5
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
print(a); afișează valoarea 8
0x5 12 De ce? Ce s-a întâmplat la apel?
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 5
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 5
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12 - Face o copie, pe stivă, a tuturor param
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 8
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12 - Face o copie, pe stivă, a tuturor param
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE ainc = 8
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12 - Face o copie, pe stivă, a tuturor param
0x4 0
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE ainc = 8
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12 - Face o copie, pe stivă, a tuturor param
0x4 0 - Execută instrucțiuni în funcție
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE ainc = 9
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12 - Face o copie, pe stivă, a tuturor param
0x4 0 - Execută instrucțiuni în funcție
0x3 4
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE ainc = 9
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12 - Face o copie, pe stivă, a tuturor param
0x4 0 - Execută instrucțiuni în funcție
0x3 4 - Golește stiva la terminarea apelului
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 9
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12 - Face o copie, pe stivă, a tuturor param
0x4 0 - Execută instrucțiuni în funcție
0x3 4 - Golește stiva la terminarea apelului
0x2 7
0x1 1
0x0 2
Exemplu didactic: procesor pe 4 biți
0xF a = 8
void inc(halfbyte a) { Apelul de
0xE 9
a++;
0xD 14
}
funcție
0xC 4
0xB 11
0xA 5 halfbyte a = 8;
0x9 0 print(a);
0x8 3
inc(a);
0x7 13
0x6 5
Un apel de funcție:
0x5 12 - Face o copie, pe stivă, a tuturor param
0x4 0 - Execută instrucțiuni în funcție
0x3 4 - Golește stiva la terminarea apelului
0x2 7
0x1 1
print(a); afișează valoarea 8
0x0 2
Alocarea dinamică a memoriei
Reminder Stivă (stack) vs Heap
Stivă Heap
• acces ff rapid • alocarea persistă și după
• se curăță automat la terminarea funcției
terminarea funcției • dimensiune nelimitată*
• spațiul gestionat eficient (nu • ceva mai lentă
se fragmentează) • trebuie să gestionăm noi
memoria (rezervăm/alocăm și
• doar pentru variabile locale eliberăm)
• dimensiune (mai mică decât • nu este gestionată eficient (se
heap-ul) dependentă de fragmentează)
sistemul de operare [1] • putem redimensiona
• dimensiunea variabilelor nu variabilele
poate fi modificată
*depinde totuși de memoria virtuală
Stivă (stack) vs Heap
Când folosim stiva? Când folosim heap-ul?
• date de dimensiuni mici • date de dimensiuni mari
• le folosim doar într-o • date care pot să-și schimbe
funcție dimensiunea în timp
• le știm de la început • date care trebuie să aibă
dimensiunea maximă (și durată de viață mare
aceasta nu se schimbă pe
parcursul programului)
null pointer
• Cum știm că un pointer este valid (îl putem
folosi)?
– un pointer este o adresă de memorie, dacă scriem
la o adresă pe care nu avem dreptul să o accesăm
=> segmentation fault
• Cum diferențiem un pointer inițializat de un
pointer neinițializat?
– amândoi pointerii punctează la o adresă care
poate fi validă
null pointer (NULL)
• avem nevoie de o adresă specială, care să nu fie validă
niciodată și care să o atribuim pointerilor ce nu pot fi
folosiți
• The language definition states that for each pointer type,
there is a special value--the ”null pointer”--which is
distinguishable from all other pointer values and which is
”guaranteed to compare unequal to a pointer to any
object or function.” That is, a null pointer points
definitively nowhere; it is not the address of any object or
function. The address-of operator & will never yield a null
pointer [3]
• in C null pointer-ul este reprezentat ca NULL și are valoarea
0
• în teorie pot exista și reprezentări diferite de 0 în memorie
pt NULL
null pointer (NULL)
• int *p;
• p=NULL; //p este inițializat cu NULL
• if(p) //sau if(p!=NULL) – verifică dacă p are o
adresă validă
• trebuie să avem grijă ca atunci când un
pointer nu mai are o adresă validă spre care să
puncteze să-i fie asignat NULL
• funcții care nu reușesc să returneze adrese
valide folosesc returnează tot NULL
Alocarea dinamică a memoriei
• alocarea dinamică a memoriei – rezervarea
unui spațiu de memorie a cărui dimensiune o
putem ști la compilare sau la rulare.
• pentru a putea utiliza spațiul rezervat adresa
de început a zonei de memorie este asignată
unui pointer
• în cazul în care alocarea nu reușește funcțiile
de alocare întorc NULL
malloc
• void* malloc (size_t size);
• alocă un număr de size octeti
• întoarce pointer la zona de date alocată sau
NULL în cazul în care alocarea nu reușește
• definită în stdlib.h
• size_t – unsigned long
Exemplu malloc
calloc
• void* calloc(size_t num, size_t size);
• num = numărul de elemente
• size = dimensiunea unui element
• toată zona de memorie alocată este inițializată cu
0
• ! ținând cont că NULL poate avea reprezentări pe
biți diferite de 0 dacă alocăm un vector de
pointeri nu este bine să ne bazăm pe inițializările
făcute de calloc
• take it with a grain of salt
Exemplu calloc
realloc
• void *realloc (void* ptr, size_t size);
• redimensionează zona de memorie spre care
punctează ptr la size octeți.
• dacă size este mai mare decât dimensiunea
inițială a blocului, zona suplimentară nu este
inițializată
• dacă realocarea nu reușește, întoarce NULL
realloc
• In cele mai multe situatii, puteti considera ca
ptr1=realloc(ptr2, ...);

• Este echivalent cu:


ptr1 = malloc(...);
memcpy(ptr1, ptr2, ...);
free(ptr2);
Exemplu realloc
free
• void free(void* ptr);
• eliberează memoria alocată și spre care
punctează pointerul ptr
• dacă ptr punctează către o zonă de memorie
care nu a fost alocată cu malloc, calloc, realloc
comportarea este nedefinită
• ptr nu este modificat de free. Este
recomandat să îi asignăm NULL după apelul
free
Exemplu free
alocare spatiu vectori
• tip_vector *v;
• v=(tip_vector*)malloc(nr_elemente*sizeof(tip_vector));
• sau
• v=(tip_vector*)calloc(nr_elemente,sizeof(tip_vector));

• Cast-urile în cazul acesta sunt descurajate în C, însă


dacă vreți să compilați codul cu un compilator C++,
atunci acestea vor deveni obligatorii
alocare spatiu matrice
• vrem sa alocam spatiu pentru o matrice [m][n]
• putem aloca un vector cu m*n elemente
– trebuie sa avem grija sa accesam elementele
corect (v[n*i+j]óv[i][j]
• alocam un vector de m pointeri si pentru
fiecare pointer alocam un vector de n
elemente
alocare matrice ca vector
alocare matrice ca vector de pointeri
• From [5]
Greșeli frecvente alocare
• nu se verifică succesul alocării
– v=(int*)malloc(n*sizeof(int));
– if(!v) //if(v==NULL) – nu s-a putut efectua alocarea
se tratează eroarea
• nu se eliberează memoria
– aveti grija sa faceti free de fiecare dată când
folosiți alocare dinamică
Greseli frecvente
• erori de logică
– se utilizează o zonă de memorie după ce a fost
eliberată
• nu se asigneaza pointerului NULL dupa eliberare si se
acceseaza o zona de memorie care poate fi curatata sau
poate sa mentina valorile (cel mai periculos)
• nu se asigneaza pointerului NULL dupa eliberare si ajungem
sa accesam o zona la care nu mai avem dreptul (seg fault)
• asignam pointerului NULL dupa eliberare sau dupa eroare
alocare dar nu verificam daca pointerul este diferit de NULL
si incercam sa-l mai folosim
VLA vs vectori alocati dinamic
• VLA • vectori alocati dinamic
int* f(int n) int *f(int n)
{ {
int v[n]; int *v=(int*)
….. malloc(n*sizeof(int));
return v; …
} return v;
- v puncteaza catre o zona de memorie }
“curatata” la parasirea functiei spatiul rezervat pentru v exista si la
- spatiul pentru v este rezervat pe stiva incheierea functiei
- spatiul pt v este limitat la dimensiunea v este alocat pe heap
stivei
- NU toate compilatoarele
implementează
Bibliografie
1. http://www.cs.nyu.edu/exact/core/doc/stackOverflow.txt
2. http://gribblelab.org/CBootcamp/7_Memory_Stack_vs_Heap.html
3. http://c-faq.com/null/index.html
4. http://en.wikipedia.org/wiki/C_data_types#stddef.h
5. http://ecomputernotes.com/what-is-c/function-a-pointer/two-dimensional-arrays-using-a-
pointer-to-pointer