Sunteți pe pagina 1din 5

Dirijarea dinamică a memoriei

În orice program, au loc anumite acţiuni de dirijare a memoriei. În primul rând,


toate variabilele care sunt utilizate în program sunt amplasate în memorie. Şi de
aceea pentru fiecare dintre ele este alocată memorie la anumite etape ale rulării
programului şi, totodată, este eliberată memoria ocupată de ele când este necesar.
O astfel de dirijare a memoriei poartă numele de dirijare statică, fiindcă
informaţia despre numărul de locaţii şi mărimea fiecărei locaţii de memorie este
cunoscută din momentul compilării. Însă dirijarea statică are un mare neajuns:
de a nu dirija totdeauna eficient memoria. De exemplu, dacă în procesul rulării
programului este necesar un tablou pentru procesarea informaţiei, dar în unele
situaţii se cer mai multe elemente, iar în altele mai puţine. Pentru a fi siguri că
în procesul procesării nu are loc depăşirea limitelor tabloului, va trebui de
determinat limita maximal posibilă a tabloului şi de definit tabloul în
corespundere cu aceste estimări. Dar o astfel de soluţionare nu este eficientă,
fiindcă în cazurile când se vor cere un număr mic de elemente pentru procesare,
celelalte elemente vor fi nefolosite, având un consum de memorie. Atunci când
dimensiunea tabloului nu este prea mare, acest fapt nu deranjează prea tare.
Dacă însă tabloul este de dimensiune mare şi sunt utilizate doar câteva
elemente, va fi un consum considerabil de memorie, ceea ce constituie un indice
nu chiar favorabil. În asemenea caz, ar fi mai eficiente nişte mecanisme
dinamice de dirijare, care ar permite alocarea memoriei strict necesare în
momentul concret al procesării.
Mecanismul de dirijare dinamică a memoriei în cadrul limbajului C este
realizat sub formă de funcţii. Există o serie de funcţii care permit diferite acţiuni în
procesul dirijării dinamice a memoriei. Aceste funcţii sunt descrise în câteva fişiere
antet, cum ar fi alloc.h, stdlib.h, care trebuie incluse în program atunci, când
se intenţionează folosirea acestor funcţii.
Pentru a aloca un anumit număr de octeţi de memorie, este utilizată funcţia
malloc() având următorul prototip:
void *malloc(size_t dim);
unde dim reprezintă mărimea în octeţi a fragmentului de memorie alocată. Funcţia
returnează adresa locaţiei de memorie la o alocare fără erori sau valoarea nulă,
exprimată prin constanta simbolică NULL, în caz de eroare. Schema generală de
alocare a unui fragment de memorie pentru N elemente de un anumit tip este
următoarea:
tip *adr_fr;
.
.
.
adr_fr=(tip *)malloc(N*sizeof(tip));
if(adr_fr!=NULL)
{ //prelucrarea necesara
.
.
}
else
{ //prelucrare in caz de erori
.
.
}

Fiindcă funcţia malloc() returnează un pointer fără tip (void *), este
necesară conversia la tipul necesar, adăugând (tip *) înainte de funcţia
malloc(), ceea ce se observă în schema propusă.
În următorul exemplu, se alocă memorie pentru a putea plasa 20 de elemente
de tip int.
int *fi;
fi=(int*)malloc(20*sizeof(int));
if(fi!=NULL)
printf(”Alocare ce succes!\n”);
else
printf(”Insucces la alocare!\n”);
Pentru a aloca memorie pentru un anumit număr de elemente de anumită
mărime este urilizată funcţia calloc()
void *calloc(size_t numar_el, size_t dim_el);
unde parametrii numar_el reprezintă numărul de elemente, iar dim_el
reprezintă dimensiunea fiecărui element din care constă fragmentul de memorie
alocată. Funcţia returnează adresa locaţiei de memorie, dacă are loc o alocare fără
erori sau valoarea nulă în caz de eroare. Schema generală de alocare a unui
fragment de memorie pentru N elemente de anumit tip este asemănătoare cu
schema din cazul precedent:
tip *adr_fr;
.
.
.
adr_fr=(tip *)calloc(N, sizeof(tip));
if(adr_fr!=NULL)
{ //prelucrarea necesara
.
.
}
else
{ //prelucrare in caz de erori
.
.
}

Şi în cazul acestei funcţii are loc conversia valorii returnate la tipul necesar.
Exemplul din cazul precedent va fi rescris astfel:
int *fi;
fi=(int*)calloc(20, sizeof(int));
if(fi!=NULL)
printf(”Alocare cu succes!\n”);
else
printf(”Insucces la alocare!\n”);
O funcţie utilă în procesul dirijării memoriei alocate este funcţia realloc().
Ea permite redimensionarea unui fragment alocat, având următorul prototip:
void *realloc(void *fr_mem, size_t dim_noua);
unde fr_mem este adresa fragmentului de memorie alocat, iar dim_noua este
marimea la care trebuie redimensionat fragmentul, măsurată în octeţi. Fragmentul
poate fi atât mărit, cât şi micşorat. Dacă la mărire fragmentul este mişcat în alt loc
al memoriei, informaţia din fragmentul vechi va fi copiată în fragmentul nou. La o
execuţie cu succes, funcţia returnează adresa fragmentului redimensionat, care
poate fi şi alta decât adresa fragmentului iniţial. La apariţia unor erori, funcţia
returnează valoarea nulă. Dacă parametrul dim_noua are valoarea zero, atunci
memoria va fi eliberată şi va fi returnată valoarea nulă. În continuare, este
prezentată schema generală de realocare a unui fragment de memorie pentru N
elemente de careva tip.
tip *adr_fr, *adr_r;

.
.
.
adr_r=(tip *)realloc(adr_fr, N*sizeof(tip));
if(adr_r!=NULL)
{ //prelucrare la o realocare cu succes
.
.
}
else
{ //prelucrare in caz de erori la realocare
.
.
}
Au fost prezentate funcţiile care permit alocarea memoriei. Însă memoria alocată
în unele situaţii trebuie şi eliberată. Pentru a putea efectua operaţia de eliberare a
memoriei, este utilizată funcţia free(), având următorul prototip:
void free(void *adr_mem);

unde adr_mem este pointerul care conţine adresa memoriei eliberate. Funcţia dată
eliberează memoria de la adresa dată şi nu returnează nici o valoare.
Exemplu. Să se alcătuiască un program care permite citirea de la tastatură a
unui şir de caractere de lungime arbitrară, memorându-l într-un tablou dinamic.

#include<stdlib.h> // sunt descrise functiile de


// alocare a memoriei
#include<conio.h>
#include<stdio.h>
#include<string.h>

char *CitireSir()
{
char *adrSir, *adrNoua, c;
int i=0, lungSir=16;
adrSir=(char*) calloc(lungSir, 1);
if (adrSir != NULL)
{
do
{
c=getche();
if(c == ’\r’) //\r – Enter
{
adrSir[i]=’\0’;
break;
}
adrSir[i] = c;
i++;
if(i>=lungSir)
{
adrNoua = realloc(adrSir, lungSir+16);
if (adrNoua == NULL)
{
adrSir[--i]=’\0’;
break;
}
else
{adrSir=adrNoua;}
lungSir+=16;
}
}
while (1);
}
adrSir = realloc(adrSir, i+1);
return adrSir;
}
//------------
void main()
{
char *sir;
sir = CitireSir();
printf(”%s\n”, sir);
getch();
free(sir);
}

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