Sie sind auf Seite 1von 15

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

Capitolul IB.10. Alocarea memoriei n limbajul C


Cuvinte cheie
Clase de memorare, alocare static, alocare dinamic, variabile
auto, variabile locale, variabile globale, variabile register, funcii
standard, vectori de pointeri, sructuri alocate dinamic

IB.10.1. Clase de memorare (alocare a memoriei) n C


Clasa de memorare arat cnd, cum i unde se aloc memorie pentru o variabil.
Orice variabil are o clas de memorare care rezult fie din declaraia ei, fie implicit din locul
unde este definit variabila.

Zona de memorie utilizat de un program C cuprinde 4 subzone:


Zona text: n care este pstrat codul programului
Zona de date: n care sunt alocate (pstrate) variabilele globale
Zona stiv: n care sunt alocate datele temporare (variabilele locale)
Zona heap: n care se fac alocrile dinamice de memorie
Moduri de alocare a memoriei:
Static: variabile implementate n zona de date - globale
Memoria este alocat la compilare n segmentul de date din cadrul programului i nu se mai poate modifica
n cursul execuiei. Variabilele externe, definite n afara funciilor, sunt implicit statice, dar pot fi declarate
static i variabile locale, definite n cadrul funciilor.
Auto: variabile implementate n stiv - locale
Memoria este alocat automat, la activarea unei funcii, n zona stiv alocat unui program i este eliberat
automat la terminarea funciei. Variabilele locale unui bloc (unei funcii) i parametrii formali sunt implicit
din clasa auto. Memoria se aloc n stiva ataat programului.
Dinamic: variabile implementate n heap
Memoria se aloc dinamic (la execuie) n zona heap ataat programului, dar numai la cererea explicit a
programatorului, prin apelarea unor funcii de bibliotec (malloc, calloc, realloc). Memoria este eliberat
numai la cerere, prin apelarea funciei free
Register: variabile implementate ntr-un registru de memorie

IB.10.2. Clase de alocare a memoriei: Auto


Variabilele locale unui bloc (unei funcii) i parametrii formali sunt implicit din clasa auto.
Durata de via a acestor variabile este temporar: memoria este alocat automat, la activarea
blocului/funciei, n zona stiv alocat programului i este eliberat automat la ieirea din
bloc/terminarea funciei. Variabilele locale NU sunt iniializate! Trebuie s le atribuim o valoare
iniial!
Exemplu:
int doi() {
int x = 2;
return x;
}
int main() {
int a;
{
int b = 5;
a = b*doi();

-1-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

}
printf(a = %d\n, a);
return 0;
}
Coninut stiv:
(x) 2
(b) 5
(a) 10

IB.10.3. Clase de alocare a memoriei: Static


Memoria este alocat la compilare n segmentul de date din cadrul programului i nu se mai poate
modifica n cursul execuiei.
Variabilele globale sunt implicit statice (din clasa static).
Pot fi declarate static i variabile locale, definite n cadrul funciilor, folosind cuvntul cheie static.
O variabil sau o funcie declarat (sau implicit) static are durata de via egal cu cea a
programului. In consecin, o variabil static declarat ntr-o funcie i pstreaz valoarea ntre
apeluri succesive ale funciei, spre deosebire de variabilele auto care sunt realocate pe stiv la
fiecare apel al funciei i pornesc de fiecare dat cu valoarea primit la iniializarea lor (sau cu o
valoare imprevizibil, dac nu sunt iniializate).
Exemple:
int f1() {
int x = 1;

/*Variabil local, iniializat cu 1 la fiecare


apel al lui f1*/

......
}
int f2() {
static int y = 99; /*Variabil local static, iniializat cu 99
doar la primul apel al lui f2; valoarea ei este
reinut pe parcursul apelurilor lui f2*/
......
}
int f() {
static int nr_apeluri=0;
nr_apeluri++;
printf("funcia f() este apelata pentru a %d-a oara\n, nr_apeluri);
return nr_apeluri;
}
int main() {
int i;
for (i=0; i<10; i++) f();
//f() apelata de 10 ori
printf("functia f() a fost apelata de %d ori.", f()); // 11 ori!!
return 0;
}

Observaii:
Variabilele locale statice se folosesc foarte rar n practica programrii ( funcia de bibliotec strtok
este un exemplu de funcie cu o variabil static).
Variabilele statice pot fi iniializate numai cu valori constante (pentru c iniializarea are loc la
compilare), dar variabilele auto pot fi iniializate cu rezultatul unor expresii (pentru c iniializarea are
loc la execuie).

Exemplu de funcie care afieaz un ntreg pozitiv n cod binar, folosind cturile mpririi cu
puteri descresctoare ale lui 10:
-2-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

// afisare intreg in binar


void binar ( int x) {
int n=digits(x);
//functie care intoarce nr-ul de cifre al lui x
int d=pw10 (n-1); //functie care calculeaza 10 la o putere intreaga
while ( x >0) {
printf("%d",x/d); //scrie catul impartirii lui x prin d
x=x%d;
d=d/10;
//continua cu x = x%d si d = d/10
}
}

Toate variabilele externe (i statice) sunt automat iniializate cu valori zero (inclusiv vectorii).

Cuvntul cheie static face ca o variabil global sau o funcie s fie privat(proprie) unitii unde a
fost definit: ea devine inaccesibil altei uniti, chiar prin folosirea lui extern.
Cantitatea de memorie alocat pentru variabilele cu nume rezult din tipul variabilei i din
dimensiunea declarat pentru vectori. Memoria alocat dinamic este specificat explicit ca parametru
al funciilor de alocare, n numr de octei.

Memoria neocupat de datele statice i de instruciunile unui program este mprit ntre stiv i
heap.
Consumul de memorie stack (stiva) este mai mare n programele cu funcii recursive (numr mare
de apeluri recursive).
Consumul de memorie heap este mare n programele cu vectori i matrice alocate (i realocate)
dinamic.
De observat c nu orice vector cu dimensiune constant este un vector static; un vector definit ntr-o
funcie (alta dect main) nu este static deoarece nu ocup memorie pe toat durata de execuie a
programului, dei dimensiunea sa este stabilit la scrierea programului. Un vector definit ntr-o
funcie este alocat pe stiv, la activarea funciei, iar memoria ocupat de vector este eliberat
automat la terminarea funciei.
Sintez variabile locale / variabile globale
O sintez legat de variabilele locale i cele globale din punct de vedere al duratai de via vs.
domeniu de vizibilitate este dat n tabelul urmtor:
Variabile globale

Variabile locale

Alocare

Static; la compilare

Auto; la execuie bloc

Durata de via

Cea a ntregului program

Cea a blocului n care e declarat

Cu zero

Nu se face automat

Iniializare

IB.10.4. Clase de alocare a memoriei: Register


A treia clas de memorare este clasa register, pentru variabile crora li se aloc registre ale procesorului i nu
locaii de memorie, pentru un timp de acces mai bun.

O variabil declarat register solicit sistemului alocarea ei ntr-un registru main, dac este
posibil.
De obicei compilatorul ia automat decizia de alocare a registrelor mainii pentru anumite variabile
auto din funcii. Se utilizeaz pentru variabile foarte solicitate, pentru mrirea vitezei de execuie.
Exemplu:
{
register int i;
for(i = 0; i < N; ++i){

-3-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

/* */
}
} /* se elibereaza registrul */

IB.10.5. Clase de alocare a memoriei: extern


O variabil extern este o variabil definit n alt fiier. Declaraia extern i spune compilatorului c
identificatorul este definit n alt fiier surs (extern). Ea este este alocat n funcie de modul de
declarare din fiierul surs.
Exemplu:
// File1.cpp
extern int i;

// Declara aceasta variabila ca fiind definita in alt fisier

// File2.cpp
int i = 88;

// Definit aici

IB.10.6. Alocarea dinamic a memoriei


Reamintim c pentru variabilele alocate dinamic memoria se aloc dinamic (la execuie) n zona
heap ataat programului, dar numai la cererea explicit a programatorului, prin apelarea unor
funcii de bibliotec (malloc, calloc, realloc). Memoria este eliberat numai la cerere, prin apelarea
funciei free.
Principalele diferene ntre alocarea static i cea dinamic sunt:
La alocarea static, compilatorul aloc i elibereaz memoria automat, ocupndu-se astfel de
gestiunea memoriei, n timp ce la alocarea dinamic programatorul este cel care gestioneaz
memoria, avnd un control deplin asupra adreselor de memorie i a coninutului lor.
Entitile alocate static sau auto sunt manipulate prin intermediul unor variabile, n timp ce cele alocate
dinamic sunt gestionate prin intermediul pointerilor!

IB.10.6. 1 Funcii standard pentru alocarea dinamic a memoriei


Funciile standard pentru alocarea dinamica a memoriei sunt declarate n fiierele stdlib.h i alloc.h.
Alocarea memoriei:
void *malloc(size_t size);
Aloc memorie de dimensiunea size octei
void *calloc(int nitems, size_t size);
Aloc memorie pentru nitems de dimensiune size octei i iniializeaz zona alocat cu
zerouri
Cele dou funcii au ca rezultat adresa zonei de memorie alocate (de tip void.

Dac cererea de alocare nu poate fi satisfcut, pentru c nu mai exista un bloc continuu de
dimensiunea solicitat, atunci funciile de alocare au rezultat NULL. Funciile de alocare au rezultat
void* deoarece funcia nu tie tipul datelor ce vor fi memorate la adresa respectiv.
La apelarea funciilor de alocare se folosesc:
Operatorul sizeof pentru a determina numrul de octei necesar unui tip de date
(variabile);
Operatorul de conversie cast pentru adaptarea adresei primite de la funcie la tipul
datelor memorate la adresa respectiv (conversie necesar atribuirii ntre pointeri de
tipuri diferite).
-4-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

Exemple:
//aloca memorie pentru 30 de caractere:
char * str = (char*) malloc(30);
//aloca memorie ptr. n ntregi:
int * a = (int *) malloc( n * sizeof(int));
//aloca memorie ptr. n ntregi si initializeaza cu zerouri
int * a= (int*) calloc (n, sizeof(int) );

IB.10.6. 2 Realocarea memoriei


Realocarea unui vector care crete (sau scade) fa de dimensiunea estimat anterior se poate face
cu funcia realloc, care primete adresa veche i noua dimensiune i ntoarce noua adres:
void *realloc(void* adr, size_t size);
Funcia realloc realizeaz urmtoarele operaii:
Aloc o zon de dimensiunea specificat prin al doilea parametru.
Copiaz la noua adres datele de la adresa veche (primul parametru).
Elibereaz memoria de la adresa veche.
Exemple:
// dublare dimensiune curenta a zonei de la adr. a
a = (int *)realloc (a, 2*n* sizeof(int));

Atenie! Se va evita redimensionarea unui vector cu o valoare foarte mic de un numr mare de ori;
o strategie de realocare folosit pentru vectori este dublarea capacitii lor anterioare.
Exemplu de funcie cu efectul funciei realloc, dar doar pentru caractere:
char * ralloc (char * p, int size) {
char *q;
if (size==0) {
free(p);
return NULL;
}
q = (char*) malloc(size);
if (q) {
memcpy(q,p,size);
free(p);
}
return q;
}

// p = adresa veche
// q=adresa noua
// echivalent cu free

//
//
//
//

aloca memorie
daca alocare reusita
copiere date de la p la q
elibereaza adresa p

// q poate fi NULL

Observaie: La mrirea blocului, coninutul zonei alocate n plus nu este precizat, iar la micorarea
blocului se pierd datele din zona la care se renun.
IB.10.6. 3 Eliberarea memoriei
Funcia free are ca argument o adres (un pointer) i elibereaz zona de la adresa respectiv (alocat
dinamic). Dimensiunea zonei nu mai trebuie specificat deoarece este memorat la nceputul zonei
alocate (de ctre funcia de alocare):
void free(void* adr);
Eliberarea memoriei prin free este inutil la terminarea unui program, deoarece nainte de
ncrcarea i lansarea n execuie a unui nou program se elibereaz automat toat memoria heap.
Exemple:
char *str;

-5-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

str=(char *)malloc(10*sizeof(char));

str=(char *)realloc(str,20*sizeof(char));

free(str);

Observaie:
Atenie la definirea de iruri n mod dinamic! irul respectiv trebuie iniializat cu adresa unui alt ir sau a
unui spaiu alocat pe heap (adic alocat dinamic)!

Exemple:
char *sir3;
char ir1[30];
// Varianta 1: sir3 ia adresa unui ir static
sir3 = sir1;
// Echivalent cu: sir3=&sir1; sir3=&sir1[0];
char *sir4="test"; //sir4 este iniializat cu adresa unui ir constant
// Varianta 2: se aloc dinamic un spaiu pe heap
sir3=(char *)malloc(100*sizeof(char));

Exemplu
Program care aloc spaiu pentru o variabil ntreag dinamic, dup citire i tiprire, spaiul fiind
eliberat. Modificai programul astfel nct variabila dinamic s fie de tip double.
Rezolvare
#include <stdlib.h>
#include <stdio.h>
int main(){
int *pi;
pi=(int *)malloc(sizeof(int));
if(pi==NULL){
puts("*** Memorie insuficienta ***");
return 1;
// revenire din main
}
printf("valoare:");
//citirea variabilei dinamice, de pe heap, de la adresa din pi!!!
scanf("%d",pi);
*pi=*pi*2;
// dublarea valorii
printf("val=%d,pi(adresa pe heap)=%p,adr_pi=%p\n", *pi, pi, &pi);
// sizeof aplicat unor expresii:
printf("%d %d %d\n",sizeof(*pi), sizeof(pi), sizeof(&pi));
free(pi);
//eliberare spatiu
printf("pi(dupa elib):%p\n",pi); // nemodificat, dar invalid!
return 0;
}

IB.10.7. Vectori alocai dinamic


Structura de vector are avantajul simplittii i economiei de memorie fa de alte structuri de date
folosite pentru memorarea unei colecii de date.

-6-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

Dezavantajul unui vector cu dimensiune fix (stabilit la declararea vectorului i care nu mai poate
fi modificat la execuie) apare n aplicaiile cu vectori de dimensiuni foarte variabile, n care este
dificil de estimat o dimensiune maxim, fr a face risip de memorie.
De cele mai multe ori programele pot afla din datele citite dimensiunile vectorilor cu care lucreaz
i deci pot face o alocare dinamic a memoriei pentru aceti vectori. Aceasta este o soluie mai
flexibil, care folosete mai bine memoria disponibil i nu impune limitri arbitrare asupra
utilizrii unor programe.
n limbajul C nu exist practic nici o diferen ntre utilizarea unui vector cu dimensiune fix i
utilizarea unui vector alocat dinamic, ceea ce ncurajeaz si mai mult utilizarea unor vectori cu
dimensiune variabil.
Un vector alocat dinamic se declar ca variabil pointer care se iniializeaz cu rezultatul funciei de
alocare. Tipul variabilei pointer este determinat de tipul componentelor vectorului.
Exemplu:
#include <stdlib.h>
#include <stdio.h>
int main() {
int n, i;
int * a;
// adresa vector alocat dinamic
printf ("n=");
scanf ("%d", &n);
// dimensiune vector
a=(int *) calloc (n,sizeof(int));
// aloca memorie pentru vector
// sau: a=(int*) malloc (n*sizeof(int));
// citire component vector:
printf ("componente vector: \n");
for (i=0;i<n;i++)
scanf ("%d", &a[i]);
// afisare vector:
for (i=0;i<n;i++)
printf ("%d ",a[i]);
return 0;

// sau

scanf (%d, a+i);

Exist i cazuri n care datele memorate ntr-un vector rezult din anumite prelucrri, iar numrul
lor nu poate fi cunoscut de la nceputul execuiei. n acest caz se poate recurge la o realocare
dinamic a memoriei. O strategie de realocare pentru vectori este dublarea capacitii lor anterioare.
n exemplul urmtor se citete un numr necunoscut de valori ntregi ntr-un vector extensibil:
Program care citete numere reale pn la CTRL+Z, le memoreaz ntr-un vector alocat i realocat
dinamic n funcie de necesiti i le afieaz.
Rezolvare:
#include <stdio.h>
#include <stdlib.h>
#define INCR 4
int main() {
int n,n_crt,i ;
float x, * v;
n = INCR;
n_crt = 0;

// dimensiune memorie alocata


// numar curent elemente n vector

-7-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

v = (float *)malloc (n*sizeof(float));

//alocare initiala

while (scanf("%f",&x) !=EOF){


if (n_crt == n) {
n = n + INCR;
v = (float *) realloc (v, n*sizeof(float) ); //realocare
}
v[n_crt++] = x;
}
for (i=0; i<n_crt; i++)
printf ("%.2f ", v[i]);
return 0;
}

Din exemplele anterioare lipsete eliberarea memoriei alocate pentru vectori, dar fiind vorba de un
singur vector alocat n funcia main i necesar pe toat durata de execuie, o eliberare final este
inutil. Eliberarea explicit poate fi necesar pentru vectori de lucru, alocai dinamic n funcii.
IB.10.8. Matrice alocate dinamic
Alocarea dinamic pentru o matrice este important deoarece folosete economic memoria i
permite matrice cu linii de lungimi diferite. De asemenea reprezint o soluie bun la problema
parametrilor de funcii de tip matrice.
O matrice alocat dinamic este de fapt un vector de pointeri ctre fiecare linie din matrice, deci un
vector de pointeri la vectori alocai dinamic. Dac numrul de linii este cunoscut sau poate fi
estimat valoarea lui maxim, atunci vectorul de pointeri are o dimensiune constant. O astfel de
matrice se poate folosi la fel ca o matrice declarat cu dimensiuni constante.
Exemplu de declarare matrice de ntregi:
int * a[M];
// M este o constanta simbolica
Dac nu se poate estima numrul de linii din matrice atunci i vectorul de pointeri se aloc dinamic,
iar declararea matricei se face ca pointer la pointer:
int** a;
n acest caz se va aloca mai nti memorie pentru un vector de pointeri (funcie de numrul liniilor)
i apoi se va aloca memorie pentru fiecare linie cu memorarea adreselor liniilor n vectorul de
pointeri.
Notaia a[i][j] este interpretat astfel pentru o matrice alocat dinamic:
a[i] conine un pointer (o adres b)
b[j] sau b+j conine ntregul din poziia j a vectorului cu adresa b.
Exemplu
S se scrie funcii de alocare a memoriei i afiare a elementelor unei matrice de ntregi alocat
dinamic.
#include<stdio.h>
#include<stdlib.h>
// rezultat adresa matrice sau NULL
int ** intmat ( int nl, int nc) {
int i;
int ** p=(int **) malloc (nl*sizeof (int*));
if ( p != NULL)
for (i=0; i<nl ;i++)
p[i] =(int*) calloc (nc,sizeof (int));

-8-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

return p;
}
void printmat (int ** a, int nl, int nc) {
int i,j;
for (i=0;i<nl;i++) {
for (j=0;j<nc;j++)
printf (%2d, a[i][j] );
printf(\n);
}
}
int

main () {
int **a, nl, nc, i, j;
printf ("nr linii i nr coloane: \n");
scanf ("%d%d", &nl, &nc);
a= intmat(nl,nc);
for (i=0;i<nl;i++)
for (j=0;j<nc;j++)
a[i][j]= nc*i+j+1;
printmat (a ,nl,nc);
return 0;

Funcia printmat dat anterior nu poate fi folosit pentru afiarea unei matrice cu dimensiuni
constante. Explicaia este interpretarea diferit a coninutului zonei de la adresa aflat n primul
argument.
Astfel, chiar dac exemplul urmtor este corect sintactic el nu se execut corect:
int x [2][2]={{1,2},{3,4}};
printmat ( (int**)x, 2, 2);

// 2 linii i 2 coloane

IB.10.9. Funcii cu rezultat vector


O funcie nu poate avea ca rezultat un vector sub forma:
int [] funcie() {}
O funcie poate avea ca rezultat doar un pointer !!
int *funcie() {}
De obicei, rezultatul pointer este egal cu unul din argumente, eventual modificat n funcie.
Exemplu corect:
// incrementare pointer p
char * incptr ( char * p) {
return ++p;
}

-9-

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

Atenie! Acest pointer nu trebuie s conin adresa unei variabile locale, deoarece:
O variabil local are o existen temporar, garantat numai pe durata executrii funciei n care
este definit (cu excepia variabilelor locale statice)
Adresa unei astfel de variabile nu trebuie transmis n afara funciei, pentru a fi folosit ulterior!!
Exemplu greit:
// vector cu cifrele unui nr intreg de maxim cinci cifre
int * cifre (int n) {
int k, c[5];
// vector local
for (k=4;k>=0;k--) {
c[k]=n%10; n=n/10;
}
return c;
// aici este eroarea !
}
//warning la compilare i POSIBIL rezultate greite n main!!

O funcie care trebuie s transmit ca rezultat un vector poate fi scris corect n n mai multe feluri:
1. Primete ca parametru adresa vectorului (definit i alocat n alt funcie) i depune
rezultatele la adresa primit (este soluia recomandat!!)
void cifre (int n, int c[ ]) {
int k;
for (k=4;k>=0;k--) {
c[k]=n%10; n=n/10;
}
}
int main(){
int a[10];
.
cifre(n,a);
.
}

2. Aloc dinamic memoria pentru vector (cu "malloc")


Aceast alocare (pe heap) se menine i la ieirea din funcie.
Funcia are ca rezultat adresa vectorului alocat n cadrul funciei.
Problema este unde i cnd se elibereaz memoria alocat.
int * cifre (int n) {
int k, *c;
// vector local
c = (int*) malloc (5*sizeof(int));
for (k=4;k>=0;k--) {
c[k]=n%10; n=n/10;
}
return c;
// corect
}

3. O soluie oarecum echivalent este utilizarea unui vector local static, care continu s existe i
dup terminarea funciei.

- 10 -

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

IB.10.10. Vectori de pointeri la date alocate dinamic


Ideea folosit la matrice alocate dinamic este aplicabil i pentru alte date alocate dinamic: adresele
acestor date sunt reunite ntr-un vector de pointeri. Situaiile cele mai frecvente sunt:
vectori de pointeri la iruri de caractere alocate dinamic
vectori de pointeri la structuri alocate dinamic.
Exemplu de utilizare a unui vector de pointeri la structuri alocate dinamic:
#include<stdio.h>
#include<stdlib.h>
typedef struct {
int zi, luna, an;
} date;
// afisare date reunite n vector de pointeri
void print_vp ( date * vp[], int n) {
int i;
for(i=0;i<n;i++)
printf ("%4d %4d %4d \n", vp[i]->zi, vp[i]->luna, vp[i]->an);
printf ("\n");
}
int main () {
date d, *dp;
date *vp[100];
int n=0;
while (scanf ("%d%d%d", &d.zi, &d.luna, &d.an) {
dp=(date*)malloc (sizeof(date));
//
alocare
structur
*dp=d;
// copiaza datele citite la dp
vp[n++]=dp;
// memoreaza adresa in vector
}
print_vp (vp,n);

dinamica

ptr

De reinut c trebuie create adrese distincte pentru fiecare variabil structur i c ar fi greit s
punem adresa variabilei d n toate poziiile din vector!
Este posibil i varianta urmtoare pentru ciclul principal din main dac cunoatem numrul de
elemente din structur:
....
scanf (%d,&n);
// numar de structuri ce vor fi citite
for (k=0; k<n; k++) {
dp = (date*) malloc (sizeof(date));// alocare dinamica ptr structur
scanf ("%d%d%d", &dp->zi, &dp->luna, &dp->an)
vp[n++]=dp;
// memoreaza adresa in vector
}
....

Exemplu
Program pentru citirea unor nume, alocare dinamic a memoriei pentru fiecare ir (n funcie de
lungimea irului citit) i memorarea adreselor irurilor ntr-un vector de pointeri. n final se vor
afia numele citite, pe baza vectorului de pointeri.
- 11 -

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

S se adauge programului anterior o funcie de ordonare a vectorului de pointeri la iruri, pe baza


coninutului fiecrui ir. Programul va afia lista de nume n ordine alfabetic.
a. Vectorului de pointeri i se va aloca o dimenisune fix.
b. Vectorul de pointeri se va aloca dinamic, funcie de numrul de iruri.
Rezolvare a:
void printstr ( char * vp[], int n) { //afisare
int i;
for(i=0;i<n;i++)
printf ("%s\n",vp[i]);
}
int readstr (char * vp[]) {
// citire siruri i creare vector de pointeri
int n=0; char * p, sir[80];
while ( scanf ("%s", sir) == 1) {
vp[n]= (char*) malloc (strlen(sir)+1);
strcpy( vp[n],sir);
//sau: vp[n]=strdup(sir);
++n;
}
return n;
}
/* ordonare vector de pointeri
bulelor)*/
void sort ( char * vp[],int n) {
int i,j,schimb=1;
char * tmp;

la

iruri

prin

Bubble

Sort

while(schimb){
schimb=0;
for (i=0;i<n-1;i++)
if ( strcmp (vp[i],vp[i+1])>0) {
tmp = vp[i];
vp[i] = vp[i+1];
vp[i+1] = tmp;
schimb = 1;
}
}
}
int main () {
int n;
char * vp[1000];
n=readstr(vp);
sort(vp,n);
printstr(vp,n);
return 0;

// vector de pointeri, cu dimens. fixa


// citire siruri i creare vector
// ordonare vector
// afiare iruri

- 12 -

(metoda

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

IB.10.11. Anexa A: Structuri alocate dinamic


n cazul variabilelor structur alocate dinamic i care nu au nume se va face o indirectare printrun pointer pentru a ajunge la variabila structur.
Avem de ales ntre urmtoarele dou notaii echivalente:
pt->camp
(*pt).camp
unde pt este o variabil care conine un pointer la o structur cu cmpul camp.
O colecie de variabile structur alocate dinamic se poate memora n dou moduri:
Ca un vector de pointeri la variabilele structur alocate dinamic;
Ca o list nlntuit de variabile structur, n care fiecare element al listei conine i un cmp
de legtur ctre elementul urmtor (ca pointer la structur).
Pentru primul mod de memorare a se vedea Vectori de pointeri la date alocate dinamic.
Liste nlnuite
O list nlnuit (linked list) este o colecie de variabile alocate dinamic (de acelai tip),
dispersate n memorie, dar legate ntre ele prin pointeri, ca ntr-un lan. ntr-o list liniar simplu
nlnuit fiecare element al listei conine adresa elementului urmtor din list. Ultimul element
poate conine ca adres de legatur fie constanta NULL, fie adresa primului element din list (lista
circular).
Adresa primului element din list este memorat ntr-o variabil cu nume i numit cap de lista
(list head). Pentru o list vid variabila cap de list este NULL.
Structura de list este recomandat atunci cnd colecia de elemente are un coninut foarte variabil
(pe parcursul execuiei) sau cnd trebuie pstrate mai multe liste cu coninut foarte variabil.
Un element din list (un nod de list) este de un tip structur i are (cel puin) dou cmpuri:
un cmp de date (sau mai multe)
un cmp de legtur
Definiia unui nod de list este o definitie recursiv, deoarece n definirea cmpului de legtur se
folosete tipul n curs de definire.
Exemplu pentru o list de ntregi:
typedef struct snod {
int val ;
struct snod * leg ;
} nod;

// camp de date
// camp de legatura

Programul urmtor arat cum se poate crea i afisa o list cu adugare la nceput (o stiv realizat ca list
nlnuit):
int main ( ) {

- 13 -

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

nod *lst=NULL, *nou, * p;


// lst = adresa cap de lista
int x;
// creare lista cu numere citite
while (scanf("%d",&x) > 0) {
// citire numar intreg x
nou=(nod*)malloc(sizeof(nod));// creare nod nou
nou->val=x;
// completare camp de date din nod
nou->leg=lst; lst=nou;
// legare nod nou la lista
}
// afisare list (fara modificare cap de lista)
p=lst;
while ( p != NULL) {
// cat mai sunt noduri
printf("%d ", pval);
// afisare numar de la adr p
p=p->leg;
// avans la nodul urmator
}
}

Cmpul de date poate fi la rndul lui o structur specific aplicaiei sau poate fi un pointer la date
alocate dinamic (un ir de caractere, de exemplu).
De obicei se definesc funcii pentru operaiile uzuale cu liste.
Exemple:
typedef struct nod {
int val;
struct snod *leg;
} nod;

// un nod de lista inlantuita


// date din fiecare nod
// legatura la nodul urmator

// insertie la inceput lista


nod* insL( nod* lst, int x) {
nod* nou ;
// adresa nod nou
if ((nou=(nod*)malloc(sizeof(nod)))==NULL)
return NULL;
nou->val=x;
nou->leg=lst;
return nou;
// lista incepe cu nou
}
// afisare continut lista
void printL ( nod* lst) {
while (lst != NULL) {
printf("%d ",lst->val);
lst=lst->leg;
}
}
int main () {
nod* lst; int x;
lst=NULL;
while (scanf("%d",&x) > 0)
lst=insL(lst,x);
printL (lst);
}

// scrie informatiile din nod


// si se trece la nodul urmtor

// creare si afisare lista stiva


// initial lista e vida
// introduce pe x in lista lst
// afisare lista

Alte structuri dinamice folosesc cte doi pointeri sau chiar un vector de pointeri; ntr-un arbore
binar fiecare nod conine adresa succesorului la stnga i adresa succesorului la dreapta, ntr-un
arbore multici fiecare nod conine un vector de pointeri ctre succesorii acelui nod.

- 14 -

INFORMATIC*I*

IB.10 Alocarea memoriei n limbajul C

IB.10.11. Anexa B: Operatori pentru alocare dinamic in C++


n C++ s-au introdus doi operatori noi:
pentru alocarea dinamic a memoriei new
pentru eliberarea memoriei dinamice delete
destinai s nlocuiasc funciile de alocare i eliberare.
Operatorul new are ca operand un nume de tip, urmat n general de o valoare iniial pentru
variabila creat (ntre paranteze rotunde); rezultatul lui new este o adres (un pointer de tipul
specificat) sau NULL daca nu exist suficient memorie liber.
Exemple:
nod * pnod;
pnod = new nod;
int * p = new int(3);

// pointer la nod de lista


// alocare fara iniializare
// alocare cu iniializare

Operatorul new are o form puin modificat la alocarea de memorie pentru vectori, pentru a
specifica numrul de componente.
Exemplu:
int * v = new int [n];

// vector de n intregi

Operatorul delete are ca operand o variabil pointer i are ca efect eliberarea blocului de memorie
adresat de pointer, a crui mrime rezult din tipul variabilei pointer sau este indicat explicit.
Exemple:
int * v;
delete v;
delete [ ] v;
delete [n] v;

// elibereaza sizeof(int) octei


// elibereaza n*sizeof(int) octei

Exemplu de utilizare new i delete pentru un vector de ntregi alocat dinamic:


#include <iostream>
#include <cstdlib>
int main() {
const int SIZE = 5;
int *pArray;
pArray = new int[SIZE];

// alocare memorie

// atribuie numere aleatoare intre 0 and 99


for (int i = 0; i < SIZE; i++) {
*(pArray + i) = rand() % 100;
}
// afisare
for (int i = 0; i < SIZE; i++) {
cout << *(pArray + i) << " ";
}
cout << endl;
delete[] pArray;
return 0;

// eliberare memorie

Dup alocarea de memorie cu new se pot folosi funciile realloc i free pentru realocare sau
eliberare de memorie.
- 15 -

Das könnte Ihnen auch gefallen