Sunteți pe pagina 1din 10

Programarea Calculatoarelor - Limbaje

Lucrarea 11. Alocarea dinamică

O1. Utilizarea metodelor de alocare dinamică în C


Obiective
O2. Utilizarea diferitelor funcții de alocare dinamică

INTRODUCERE

Alocarea dinamică permite crearea, exploatarea şi distrugerea unor obiecte în timpul execuției
programului, la inițiativa programatorului. Se foloseşte dacă se poate obține o reducere a dimensi-
unii programului prin reducerea zonei de date incluse în program. Se foloseşte în cazul datelor de
dimensiune variabilă sau în cazul unor structuri cu număr variabil de elemente, număr cunoscut
abia la execuție.
Odată alocată memoria, acea zona poate fi tratată ca fiind un tablou și accesată astfel, pentru
că alocarea se face în mod secvențial.
Limbajul C nu dispune de un sistem încorporat pentru alocarea şi eliberarea variabilelor dinam-
ice, așa cum are pentru variabile statice şi locale. Biblioteca standard C oferă un set de funcții pen-
tru alocarea şi eliberarea variabilelor dinamice. Funcțiile ce permit alocarea dinamică sunt de-
clarate în fişierele antet:
stdlib.h
Alocarea dinamică implică folosirea pointerilor. Este necesară folosirea conversiilor de tip şi a
operatorului sizeof(). Pointerii obtinuți cu funcțiile malloc() şi calloc() se vor dealoca numai cu
funcția free().
Se recomandă testarea pointerilor obținuți înainte de folosire şi înainte de dealocare!!!

MALLOC()
void* malloc(unsigned nr_oct);

• alocă o zonă de memorie de dimensiune nr_oct octeți în memoria heap


• returnează un pointer generic, în caz de succes, sau valoarea NULL
• dimensiunea maximă ce poate fi alocată depinde de sistemul de operare,
Pointerul generic este convertit cu operatorul cast, iar dimensiunea memoriei este calculată cu
operatorul sizeof astfel:
int *p, n=20;
p = (int *) malloc(n * sizeof(int));

Zona de memorie alocată este echivalentă cu un tablou de 20 de întregi, iar elementele lui pot fi
referite:
• cu operatorul de indexare: p[0], p[i]
• sau cu operatorul de indirectare: *p, sau mai general, *(p+i)
Se recomandă testarea pointerului obținut înainte de folosire!!

© Adriana Stan, Ligia Chiorean, Mircea Vaida 1 Programarea Calculatoarelor - Limbaje


CALLOC()
void* calloc(unsigned nr_elem, unsigned dim_elem);

• alocă o zonă de nr_elem*dim_elem octeți în memoria heap


• inițializează zona de memorie cu 0
• returnează un pointer generic, în caz de succes, sau valoarea NULL

FREE()
void free(void *);

Permite eliberarea zonelor de memorie alocate anterior, prin specificarea unui pointer ce
conține adresa de început a zonei ce se dorește a fi eliberată. Dacă se apelează cu un parametru
NULL rezultatele sunt imprevizibile.
Dacă datele din heap nu mai sunt necesare se recomandă eliberarea zonei aferente
După eliberare:
• nu poate folosi din nou acea zonă de memorie cu pointerul eliberat
• pointerul eliberat rămâne vizibil, dar valoarea lui nu are nici o semnificație
• până la sfârșitul blocului acest pointer poate fi refolosit la o altă alocare sau ca simplu pointer
către o dată căreia i se asociază

Regulă practică: numărul de apeluri către funcții de alocare trebuie să fie egal cu numărul de
apeluri către funcții de dealocare

REALLOC()
void *realloc(void *block, size_t size);

Permite realocarea memoriei prin extinderea sau comprimarea unui bloc ce a fost alocat anteri-
or cu una din funcțiile malloc(), calloc() sau chiar realloc()
• dacă size == 0 blocul de memorie este eliberat şi se returnează valoarea NULL
• dacă block == NULL, funcția realloc( ) lucrează la fel ca şi funcția malloc( )
• funcția returnează un pointer la zona de memorie realocată în caz de succes sau valoarea
NULL în caz de eşec sau dacă size == 0
• în urma ajustării dimensiunii blocului de memorie este posibilă mutarea conținutului memoriei
în altă zonă, datele fiind păstrate

Funcții pentru manipularea zonelor de memorie

Inițializare zonă de memorie


#include <memory.h> // sau <string.h>
void *memset(void *dst, int c, size_t n);

© Adriana Stan, Ligia Chiorean, Mircea Vaida 2 Programarea Calculatoarelor - Limbaje


Funcția setează primii n octeți începând cu adresa dst la valoarea dată de caracterul conținut în
parametrul c şi returnează adresa şirului pe care lucrează

Copierea zonelor de memorie


#include <memory.h> // sau <string.h>
void *memcpy(void *dest, const void *src, size_t n);

copiază un bloc de memorie de lungime n de la adresa src la adresa dest. Nu se garantează o


funcționare corectă în cazul în care blocul sursa şi cel destinație se suprapun. Funcția returnează
adresa blocului destinație.

#include <memory.h> // sau <string.h>


void *memccpy(void *dest, const void *src, int c, size_t n);

copiază n octeți de la sursă la destinație, însă copierea se poate opri în următoarele situații:
• la întâlnirea caracterului c (ce este copiat la destinație)
• s-au copiat deja n octeți la adresa de destinație
Returnează adresa din blocul destinație ce urmează după caracterul c, dacă acesta a fost copi-
at sau valoarea NULL în caz contrar

Mutarea zonelor de memorie

#include <memory.h> // sau <string.h>


void *memmove(void *dest, const void *src, size_t n);

• se mută un bloc de lungime n de la adresa sursă src la adresa destinație dest


• se garantează copierea corectă chiar dacă cele două zone de memorie se suprapun
• funcția returnează adresa zonei destinație

Compararea zonelor de memorie


#include <memory.h> // sau <string.h>
int memcmp(const void *s1, const void *s2, unsigned n);
int memicmp(const void *s1, const void *s2, unsigned n);

memcmp() compară primii n octeți ai zonelor de memorie s1 şi s2 şi returnează un întreg mai


mic decât, egal cu, sau mai mare decât zero dacă s1 este mai mic decât, coincide, respectiv este
mai mare decât s2

memicmp() face acelaşi lucru, dar fără a ține cont de litere mari, respectiv litere mici (ignoring
case) - DOAR ÎN COMPILATOARE MICROSOFT!!

Interschimbarea octeților

#include <stdlib.h>
© Adriana Stan, Ligia Chiorean, Mircea Vaida 3 Programarea Calculatoarelor - Limbaje
void swab(char *src, char *dest, int n);

preia primii n octeți de la sursă, aplică interschimbarea fiecărei perechi şi depune rezultatul la
destinație
dacă n este par, interschimbarea se aplică pentru toți octeții, începând cu primul octet
dacă n este impar, interschimbarea se aplică numai la primii (n-1) octeți, începând cu primul
octet

EXEMPLE

1. Program pentru alocarea unui tablou unidimensional folosind funcţii de bibliotecă.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main(void){
int i,n, *tab=NULL;
printf("\nIntroduceti dimensiunea tablolului: ");
scanf("%d", &n);
if((tab = (int *)malloc(n * sizeof(int)))) {
printf("\nIntroduceti elementele tablolului: \n");
for(i=0; i<n; i++) {
printf("\t elementul %d: ", i+1);
scanf("%d", tab+i);
}
for(i=0; i<n; i++)
printf("\n tab[%d] = %d", i, tab[i]);
//printf("\n tab[%d] = %d", i, *(tab +i));
printf("\n");
}
else
printf("\nAlocare nereusita !");
if(tab)
free(tab);
}

2. Alocare tablou dinamic unidimensional exploatat ca unul bidimensional.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

int main(void){

© Adriana Stan, Ligia Chiorean, Mircea Vaida 4 Programarea Calculatoarelor - Limbaje


int *tab, m, n, i, j;

printf("\n Introduceti doua numere intregi pozitive: ");


scanf("%d %d", &m, &n);
if((m <= 0) || (n <= 0)) {
printf("\nNumere invalide ! Mai incearca !");
return 0;
}// end if

// alocare dinamica si test pointer


if((tab = (int *)malloc(m * n * sizeof(int)))){
printf("\nIntroduceti elementele matricei:");
for(i=0; i<m; i++) {
printf("\nLinia %d :", i+1);
for(j=0; j<n;j++)
scanf("%d", tab+i*n+j);
}// end for

// aici se pot face si alte prelucrari...


printf("\nMatricea arata astfel:");
for(i=0; i<m; i++){
printf("\n\t");
for(j=0; j<n;j++)
printf("%d ", *(tab+i*n+j));
}// end for
printf("\n");
}//end if
else{
printf("\n Eroare de alocare !");
return 0;
}//end else

// dealocare
if(tab)
free(tab);
}// end main

3. Alocarea unui tablou bidimensional (matrice); citire şi afişare elemente.

#include <stdio.h>
#include <stdlib.h>

int main(void){
int i, j, m,n, **tab;
printf("\n Introduceti numarul de linii: ");
scanf("%d", &m);
if((tab = (int **)malloc(m*sizeof(int)))){
printf( "\n Introduceti numarul de coloane: ");

© Adriana Stan, Ligia Chiorean, Mircea Vaida 5 Programarea Calculatoarelor - Limbaje


scanf("%d", &n);
for(i=0; i<m; i++){
tab[i] = (int *) malloc(n*sizeof(int));
if(tab[i] == 0){
printf("\n Eroare de alocare !");
return 0;
}
}
printf("\n Introduceti elementele tabloului:");
for(i=0; i<m; i++){
printf("\n\t Linia %d:\n", i+1);
for(j=0; j<n; j++) {
printf("\t Elementul tab[%d][%d]: ", i+1, j+1);
scanf("%d", &tab[i][j]);
}
}

printf("\n\n Elementele tabloului sunt: \n");


for(i=0; i<m; i++){
for(j=0; j<n; j++)
printf("\t%d", tab[i][j]);
printf("\n");
}
}
else
printf("Alocare nereusita !");

if(tab){
for(i=0; i<m; i++)
free (tab[i]);
free(tab);
}
return 0;
}

4. Inițializare zonă de memorie


#include <stdio.h>
#include <memory.h>

int main(void){
char str[] = "abcdefghijklmnopqrstuvwxyz";
printf("%s\n", str);
memset(str,'a',5);
printf("%s\n", str);
}//end main

5. Copierea unei zone de memorie

© Adriana Stan, Ligia Chiorean, Mircea Vaida 6 Programarea Calculatoarelor - Limbaje


#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int main(void){
char source[] = "a fost odata ca-n povesti";
char dest[6];
memcpy(dest, source, sizeof dest);
for(size_t n = 0; n < sizeof dest; ++n)
printf("%c",dest[n]);
}//end main

6. Mutarea unei zone de memorie


#include <stdio.h>
#include <memory.h>
#include <stdlib.h>

int main(void){
float values[ ] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
float empty[5];
int i;
memmove(empty, values, sizeof(values));
for (i = 0; i < 5; i++)
printf("%3.1f\t", empty[i]);
printf("\n");
}

7. Compararea zonelor de memorie

#include <stdio.h>
#include <stdlib.h>

int main(void){
char *a = "AAA";
char *b = “aaa";

printf("Rezultatul compararii %s cu %s folosind memcmp( )


este: %d\n", a, b, memcmp(a, b, sizeof(a)));
printf("Rezultatul compararii %s cu %s folosind memicmp( )
este: %d\n", a, b, memicmp(a, b, sizeof(a)));
}//end main

8. Căutarea într-o zonă de memorie


#include <stdio.h>
#include <string.h>

© Adriana Stan, Ligia Chiorean, Mircea Vaida 7 Programarea Calculatoarelor - Limbaje


int main(void)
{
char str[] = "ABCDEFG";
char *ps = (char *) memchr(str,'D',strlen(str));
if (ps != NULL)
printf ("Caracterul cautat a fost gasit: %s\n", ps);
else
printf ("Caracterul cautat nu a fost gasit\n");

return 0;
}

9. Interschimbarea octeților

#include <stdio.h>
#include <memory.h>
#include <string.h>

int main(void) {
char *source = "ABCD";
char target[10];
memset(target, NULL, sizeof(target));
swab(source, target, strlen(source));
printf("Sursa: %s \n", source);
printf("Destinatie: %s\n", target);

char *source2 = "ABCDE";


char target2[10];
memset(target2, NULL, sizeof(target2));
swab(source2, target2, strlen(source2));
printf("Sursa: %s \n", source2);
printf("Destinatie: %s\n", target2);
}

TEME
1. Să se scrie un program care citeşte n numere reale, pe care le stochează într-un tablou alocat
dinamic, afişează suma elementelor negative citite, iar la sfârşit eliberează zona de memorie
alocată.

© Adriana Stan, Ligia Chiorean, Mircea Vaida 8 Programarea Calculatoarelor - Limbaje


2. Fie o aplicaţie de gestiune distribuită care consideră că tratează activitatea din 5 oraşe diferite.
În fiecare oraş sunt 3 birouri de vânzare. Să se creeze în cadrul unei funcţii un tablou de 5 point-
eri către date de tip flotant, fiecare pointer din acest tablou referind o zonă în heap alocată di-
namic de 3 date flotante ce reprezintă situaţia vânzărilor la sfârşitul unei zile. Se cere prelucrarea
datelor din fiecare oraş, respectiv din fiecare birou de vânzare, prelucrare ce va include:
• funcţie care permite introducerea datelor pentru cele 5 oraşe şi respectiv pentru fiecare oraş
datele pentru cele 3 magazine din oraş;
• funcţie ce permite determinarea totalului de vânzări pe fiecare oraş în parte, valoare pe care o
va returna astfel că în programul principal se va calcula şi afişa media vânzărilor din toate cele
5 oraşe;
• funcţie care va permite eliberarea spaţiului de memorie alocat dinamic astfel încât dacă
aceeaşi firmă are alte 3 magazine în cele 5 oraşe de profil diferit să poată realoca un spaţiu
echivalent pentru noile prelucrări pe care le va efectua.
3. Să se scrie o aplicaţie C, care alocă dinamic memorie pentru stocarea elementelor a două ma-
trici de "m" linii şi "n" coloane. Să se scrie o funcţie care calculează suma celor două matrici şi o
funcţie pentru afişarea unei matrici. Să se afişeze matricile iniţiale şi matricea obţinută.
4. Să se scrie o aplicaţie C care alocă dinamic memorie pentru "n" şiruri de caractere, care se
vor citi de la tastatură.
5. Declaraţi un pointer global de tip float. În funcţia main() citiţi o valoare întreagă N care reprez-
intă dimensiunea tabloului de numere reale. Alocaţi memoria necesară pentru stocarea tabloului
şi citiţi elementele de la tastatură. Determinaţi valoarea medie a celor N elemente şi calculaţi
Mn=(sum(pow((xi-xmed),n))/N, unde n=1,2,3. Afişaţi rezultatele şi apoi eliberaţi memoria. Folosiţi
funcţiile malloc() şi free(). Generaţi numerele din tablou folosind funcţia de bibliotecă care
generează numere aleatoare şi determinaţi pentru acestea media valorilor şi Mn.

6. Folosiţi alocarea dinamică pentru o matrice m x n cu valori întregi (m, n <7). Initializaţi ele-
mentele matricii. Dacă matricea este pătratică, folosiţi metoda lui Sarrus pentru a obţine valoarea
determinantului. Afişaţi rezultatul şi eliberaţi memoria.
7. Să se scrie o aplicaţie C care alocă dinamic memorie necesară pentru stocarea a 10.000 de
numere întregi. Programul iniţializează numerele cu valori aleatoare între 1 şi 100 (folosiţi funcţia
rand()). Scrieţi o funcţie care afişează cele mai frecvente 10 numere şi numărul lor de apariţii în
tabloul iniţial.
8. Să se scrie o aplicaţie C în care se alocă dinamic memorie pentru n numere întregi, numere
ce vor fi citite de la tastatură. Să se scrie funcţia care extrage radicalul din fiecare număr şi
stochează valorile obţinute într-un alt tablou alocat dinamic. Să se afişeze numerele iniţiale şi
valorile din tabloul format. Eliberaţi la sfârşit memoria alocată.
9. Scrieţi un program în care se citesc n şiruri de caractere şi se concatenează într-un alt şir, alo-
cat dinamic. Repetaţi operaţia de câte ori doreşte utilizatorul. După fiecare afişare a şirului obţin-
ut prin concatenare eliberaţi memoria alocată dinamic.

10. Să se scrie o aplicaţie C, care alocă dinamic memorie pentru stocarea elementelor unei ma-
trici de dimensiune nxn. Să se scrie o funcţie care calculează suma numerelor pozitive pare de
sub diagonala principală şi o funcţie pentru afişarea matricei. Să se afişeze matricea şi suma
cerută. Eliberaţi memoria alocată dinamic.
11. Generați un tablou de pointeri către șiruri constante folosind funcția strdup() sau o funcție
specifică. Afișați valorile pare din tablou.

© Adriana Stan, Ligia Chiorean, Mircea Vaida 9 Programarea Calculatoarelor - Limbaje


© Adriana Stan, Ligia Chiorean, Mircea Vaida 10 Programarea Calculatoarelor - Limbaje

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