Sunteți pe pagina 1din 5

Pointeri Alocarea dinamică (Pointers and dynamic memory).

Multe aplicații pot fi optimizate dacă memoria necesară stocării datelor lor este alocată dinamic
în timpul execuției programului. Alocarea dinamică de memorie înseamnă alocarea de zone de
memorie și eliberarea lor în timpul execuției programelor. Zona de memorie în care se alocă, la
cerere, datele dinamice este diferită de zona de memorie în care se alocă datele statice (stiva de
date) şi se numește heap.
Spațiul de memorie alocat dinamic la cerere este accesibil programatorului printr-un pointer
care conține adresa sa. Pointerul care indică un obiect de pe heap este de regulă stocat într-o
variabilă alocată static.

De obicei într-o arhitectură tipică a unui calculator, memoria poate fi separată


în 4 segmente (secțiuni).
O secțiune de memorie este prevăzut pentru stocarea instrucțiunilor care
trebuie să fie executate. Altă secțiune este prevăzută pentru stocarea variabile globale
sau statice care nu sunt declarate în funcția main() sau alte funcții și sunt vii pe tot
parcursul ciclului executării programului (accesibile oriunde).
Următoarea secțiune (Stack) este utilizată pentru apelarea funcțiilor și toate variabilele
locale.

#inlcude<stdio.h>
int total; Iată un program care are 2 funcții.
int Square(int x) Prima Square() cu un argument, ne returnează patratul unui număr.
{ Square_Sum() –cu 2 argumente, returnează suma a 2 numere.
Return x*x; Să presupunem că stiva de jos reprezintă memoria programului în timpul execuției.
} Cînd programul începe să se execute, funcția
int Square_Sum (int x, int y) main() este implicată pentru prima operație,
{ astfel se va aloca memoria pentru ea in Stack.
int z= Square (x+y);
return z; Toate variabilele locale, argumentele și
} datele care trebuie să fie returnate sunt
int main () stocate aici în stack-frame. Mărimea acestui
{ stack este calculat atunci când programul este dat
Int a=4, b=8; la compilare.
total=Square_Sum(a,b);
Printf(”output =%d”,total);
}

Când main() apelează Square_Sum(int x) și Square(int x,int y),el


le alocă memoria necesară lor.
În acest moment vom avea aceste 3 metode stocate în stivă (stack). În orice timp în
timpul execuției programului, funcția și topul acestui stack se execută și face o
pauză,așteptînd să returneze ceva, apoi va relua execuția. (Astfel sunt desenate
pictogramele de rulare și de stop).

Funcțiile se vor executa rând pe rând, returnând rezultatul așteptat , eliberând


memoria (Vor dispărea din stack rând pe rând). Când acest stack se termină el va
returna.

1
Se va relua funcția main(), apoi instrucțiunea printf() apare în top la stack și se
execută. Printf () este eliberată din memorie, revine în main() și mai apoi și main () se
eliberează din memorie. Apoi se șterge și variabila globala total. Nu era necesar să utilizăm
această variabilă locală. Utilizăm variabile globale numai în cazul când e necesar de folosit
în diferite părți ale programului. În caz contrar irosim spațiu de memorie pe tot parcursul
programului.

Va trebui de specificat ceva detalii aici, când programul se dă la execuție, Sistemul de


operare îi alocă spațiul necesar acestuia. Să presupunem 1MB. De obicei se alocă memorie ca
stack doar atît timp cît rulează programul.
Dacă apar apelări la funcții care depășește memoria rezervată acesteia, atunci
aceasta se numește stackoverflow astfel programul nu va funcționa, va ruina (it will crash).
Așa cum putem observa există careva limite în alocarea memoriei.
- Volumul memoria stack nu crește în timpul executării.
- -Aplicația nu poate cere mai mult spațiu.
Dacă apelul stack-ului crește dincolo de spațiul rezervat al memoriei pentru stack
(1Mb), ca de ex: o metodă A apelează B, la rîndul său B apelază C și tot așa apelînd în
lanț, noi epuizăm tot spațiu de memorie alocată pentru stack (are loc stackoverflow).
- O altă eroare des întîlnită este programarea incorectă (bad code) formând recursiuni
după care se formează ciclu (ri) infinit (e). Programul se execută la infinit.
- Alocarea dinamică de memorie și eliberarea lor în timpul execuției programelor are loc după un set de reguli
exacte. Cînd o funcție este apelată ea este plasată în topul stack-ului și apoi eliberată.
- Dacă avem nevoie să declarăm un tip de date mai mare precum un tablou ca o variabilă locală, atunci avem
nevoie să știm mărimea tabloului doar în timpul execuției. Pentru toate aceste probleme precum alocarea unui spațiu
de memorie voluminos or staționarea variabililor în memorie atât timp cât dorim, Utilizăm HEAP.
Spre deosebire de Stack, Heap are o memorie care poate varia în timpul execuției programului. Nu există seturi
de reguli precum alocarea și eliberarea spațiului de memorie. Programul totalmente poate controla cîtă memorie se va
utiliza în HEAP și cât timp. La fel spațiul poate varia adică să crească și să scadă, astfel fiind sigur că programul va avea
suficient spațiu de memorie alocat.
Heap – spațiu liber de rezervare, sau memorie dinamică.
Pentru a folosi în C memoria dinamică este nevoie să știm despre 4 funcții:
- malloc
- calloc
- realloc
- free
Iar în C++ funcții:
- new
- delete
În realitate mărimea stack-lui va depinde de arhitectura și tipul OS și a compilatorului. Este o chestie dependentă de
arhitectura calculatorului.

2
#include <stdio.h>
#include<stdlib.h>
int main()
{
int a; // goes on stack
int *p;
p=(int *) malloc sizeof(int)); // to reserve on a heap , give me a bloc of memory
2 //bytes of int.
// ii alocam un block de memorie din heap. Dar ea este goala. Adresa 200
*p=10;// daca vrem sa-I dam o valoarea atunci ii atribuim valoarea .

free(p); // elibereaza memoria.

p= (int*) malloc(sizeof(int));// alocam inca un bloc de memorie in heap


*p=20; // adresa 400
/*alocam dynamic memorie, blocul precedent încă va exista in heap
, astfel noi consumam spațiu de memorie. Nu este ștearsa sau eliberata automat.
Memoria este o sursa importanta de aceia este nevoie de eliberat spațiul de memorie
care nu se va mai utiliza.
Se executa cu funcția free, daca nu ștergem pointerul încă se va referi la primul bloc cu
var 10 si adresa 200. */

/*daca dorim să alocăm spațiu unui tablou de tip int cu 20 elemente in heap, totul ce
facem e sa apelam funcția */
p=(int *)malloc(20 * sizeof(int));/* cerând un bloc cu 20 de elemente de tip int, unde
pointerul arata spre prima adresa a elementului tabloului. */

/*Un lucru important aici, dacă nu putem să alocăm memorie dinamica cuiva se va
returna NULL. */
}

In C++ nu este mare diferentă pentru alocarea dinamică.

3
void *p=malloc (4)// radnomly alocate 4 bytes
printf(”p=”,p); // 208

De ce alocăm aleatoriu?
De ce noi alocăm spațiu de memorie? Noi alocăm memorie pentru a stoca careva date in
heap. Nu dorim să alocam aleatoriu spațiu de memorie. Trebuie să știm exact căt alocăm.
Dacă dorim să alocăm pentru un int (stim că fiecare bloc are un byte) atunci utilzăm
expresia:

void *p=malloc (sizeof(int))// randomly alocate 4 bytes


printf(”p=”,p); // 208

Dacă avem nevoie de 10 int atunci:


void *p=malloc (10 *sizeof(int))// randomly alocate 4 bytes
printf(”p=”,p); // 208

Pentru inițializarea pointerilor.


int *p=malloc (10 *sizeof(int))// randomly alocate 4 bytes
printf(”p=”,p); // 208

*p=2;
*(p+1)=4;

*(p+1);

Ori

p[0]=2;
p[1]=4;

p[i]=x;

Calloc - face aceiași chestia ca funcție malloc dar are 2 specificații:


sintaxa
Void *calloc(size_t num, size_t size)

4
Alocarea de memorie pentru un vector şi inițializarea zonei alocate cu zerouri se poate face cu funcția calloc.
În timp ce funcția malloc() ia un singur parametru (o dimensiune în octeţi), funcția calloc() primeşte două argumente, o
lungime de vector şi o dimensiune a fiecărui element.

Realoc.
Realocarea unui vector care creşte (sau scade) faţă de dimensiunea estimată anterior se poate face cu funcţia realloc, care
primeşte adresa veche şi noua dimensiune şi întoarce noua adresă

S-ar putea să vă placă și