Sunteți pe pagina 1din 7

PROGRAMAREA CALCULATOARELOR ____________________________________________ Laborator Nr.

LABORATOR NR. 7
POINTERI. ALOCAREA DINAMICĂ A MEMORIEI

1. Pointeri
Un pointer este o variabilă care conține adresa unei zone de memorie rezervată pentru o variabilă sau
o funcție (dacă pointerul este inițializat cu adresa variabilei sau a funcției) sau adresa unei zone de memorie
rezervată în urma unei alocări dinamice de memorie.
ATENȚIE: tablourile (cu una sau mai multe dimensiuni) cu lungime variabilă NU sunt pointeri.

Definirea unei variabile pointer:


int *pi = 0; // pi este pointer la întreg - poate conține adresa unui întreg
double *pd = 0; // pd este pointer la double - poate conține adresa unui double

Aflarea adresei unei variabile și extragerea conținutului unei adrese


int x=3, y;
int *pi = &x; // pi conține adresa lui x
y = *pi; // extrage conținutul de la adresa din variabila pi
// (adica valoarea lui y este tot 3)
*pi = 5; // x devine 5, y rămâne la valoarea 3

TEMA 1
Problema nr. 1.1
Scrieți un program în C pentru a demonstra utilizarea operatorilor & și *.
Se citesc de la tastatură un caracter z, un număr întreg m și un număr real fx. Să se definească 3
pointeri (câte unul pentru fiecare tip de variabilă).
Se afișează valorile citite de la tastatură (ieșirea trebuie să fie de următoarea formă):
m = 300
fx = 300.600000
cht = z

Să se afișeze valorile adreselor celor 3 variabile (după modelul următor)


Obs: Valorile adreselor pot fi altele:
Valori obținute prin folosirea operatorului de referențiere
adresa lui m = 0x7ffda2eeeec8
adresa lui fx = 0x7ffda2eeeecc
adresa lui cht = 0x7ffda2eeeec7

Să se afișeze valorile obținute prin dereferențierea adresei unei variabile (se folosesc operatorii de
referențiere și dereferențiere – o construcție de forma *(&a) ):
Valori obținute prin folosirea operatorilor & si *
valoarea de la adresa lui m = 300
valoarea de la adresa lui fx = 300.600000
valoarea de la adresa lui cht = z

Să se inițializeze pointerii cu adresele variabilelor definite mai sus. Să se afișeze valorile pointerilor:
Adrese obținute prin folosirea valorilor pointerilor
valoarea pointerului cu adresa lui m = 0x7ffda2eeeec8

1
PROGRAMAREA CALCULATOARELOR ____________________________________________ Laborator Nr. 7

valoarea pointerului cu adresa lui fx = 0x7ffda2eeeecc


valoarea pointerului cu adresa lui cht = 0x7ffda2eeeec7

Să se afișeze valorile obținute prin dereferențierea unui pointer:


Valori obținute prin dereferențierea pointerilor
valoarea de la adresa lui m = 300
valoarea de la adresa lui fx = 300.600000
valoarea de la adresa lui cht = z

Problema nr. 1.2


Scrieți un program care să adune două numere folosind pointeri (se citesc două valori întregi, se extrag
adresele lor în doi pointeri și se face adunarea prin folosirea dereferențierii).

Problema nr. 1.3


Scrieți un program care să calculeze maximul dintre două numere folosind pointeri (se citesc două
valori întregi, se extrag adresele lor în doi pointeri și se determină maximul prin folosirea dereferențierii).

2. Alocarea dinamică a memoriei


void *malloc(size_t n);
– alocă un bloc de memorie de n octeți în memoria heap;
– în caz de succes, returnează un adresa zonei de memorie alocate (căreia nu-i schimbă conținutul)
– returnează valoarea 0 (zero) dacă nu s-a putut face alocarea de memorie (pentru că nu există spațiu
liber cu mărimea solicitată sau dacă se apelează cu n = 0).
Funcția returnează un pointer generic (de tip void *), a cărui valoare poate fi asignată unui pointer de
orice tip folosind o conversie explicită.
Întotdeauna trebuie testată valoarea returnată (dacă este sau nu 0 (zero)) pentru că în cazul nealocării
memoriei programul nu trebuie să continue.
Exemplu:
int *p = 0;
int n = 5;
p = (int *)malloc(n * sizeof(int));
if(p == 0)
{
fprintf(stderr, "Memorie insuficienta\n");
exit(EXIT_FAILURE);
}

void *calloc(size_t nrElemente, size_t dimElement);


– alocă un bloc de memorie de mărime nrElemente * dimElement, conținutul blocului fiind resetat
(se scrie 0 în toți octeții);
– în caz de succes, returnează adresa blocului de memorie alocat;
– returnează 0 dacă nu există spațiu liber de mărimea solicitată (sau dacă se apelează cu valoarea 0).

void *realloc(void* block, size_t marime);


– funcția redimensionează (prim mărire sau micșorare) un bloc de memorie (alocat dinamic anterior)
la numărul de octeți specificați de parametrul marime;

2
PROGRAMAREA CALCULATOARELOR ____________________________________________ Laborator Nr. 7

– block trebuie să indice un bloc de memorie obținut prin apelarea funcțiilor malloc() / calloc() /
realloc() (altfel rezultatul este imprevizibil);
– dacă block este 0 (zero), lucrează exact ca malloc();
– funcția ajustează mărimea blocului alocat la marime, copiind (dacă este cazul) conținutul său la o
nouă adresă;
– returnează adresa blocului realocat (poate diferi de block) sau 0 (zero), dacă nu se poate face
realocarea sau marime = 0 (în acest ultim caz funcția lucrează ca și funcția free()).

void free(void *block);


– eliberează un bloc de memorie alocat anterior de către malloc() / calloc() / realloc();
– rezultatul este dezastruos dacă parametrul nu este rezultatul unei alocări dinamice anterioare sau
dacă se apelează de două ori la rând cu același parametru.
– după folosirea funcției free se recomandă invalidarea pointerului (pentru a nu mai putea fi folosit
accidental în continuare) prin atribuirea valorii 0 (zero) (vezi exemplul următor).
Exemplu:
int *p = 0;
int n = 3;
/*
* Alte definiri de date și instrucțiuni
*/

...................................

p = (int *)malloc(n * sizeof(int));


if(p == 0) // sau if(0 == p)
{
fprintf(stderr, "Memorie insuficienta\n");
exit(EXIT_FAILURE);
}
/*
* Prelucrari de date
*/

.........................................

/*
* Eliberarea memoriei
*/
memset(p, 0, n * sizeof(int)); //Obligatoriu pentru a șterge memoria folosită
free(p);
p = 0; // Obligatoriu pentru a invalida pointerul

3
PROGRAMAREA CALCULATOARELOR ____________________________________________ Laborator Nr. 7

TEMA 2
Problema nr. 2.1
Să se citească de la tastatură elementele unui vector cu n elemente numere întregi și să se afișeze pe
monitor. Vectorul este alocat dinamic în funcția main și după afișarea elementelor lui, se va face dealocarea
memoriei folosite (tot în main). Vor trebui scrise două funcții:
ü funcție pentru citirea unui vector de întregi cu n elemente. Funcția trebuie să aibă următorul
prototip:
void pcitireVectorInt(int *a, int n);
ü funcție pentru afișarea elementelor unui vector de întregi, cu prototipul:
void pafisareVectorInt(int *a, int n);

Problema nr. 2.2 – rezolvată la curs


Să se citească de la tastatură elementele a două tablouri unidimensionale (vectori) de n numere întregi
a și b alocate dinamic. Să se calculeze vectorul sumă și produsul scalar și să se afișeze rezultatele obținute.
Rezolvarea problemei presupune construirea unui proiect (cu fișierul header corespunzător) și scrierea
următoarelor funcții:
ü funcție pentru citirea unui vector de întregi cu n elemente. Funcția trebuie să aibă următorul
prototip:
void pcitireVectorInt(int *a, int n);
ü funcție pentru afișarea elementelor unui vector de întregi, cu prototipul:
void pafisareVectorInt(int *a, int n);
ü funcție pentru calculul vectorului sumă a doi vectori, cu prototipul:
int *sumaVectoriInt(int *x, int *y, int n);
ü funcție pentru calculul produsului scalar a doi vectori, cu prototipul:
int produsScalarVectoriInt(int *x, int *y, int n);

Observație: Se va folosi același fișier header și același fișier cu funcții proprii ca la Problema 2.1.
(completate cu funcțiile pentru Problema 2.2)

Problema nr. 2.3


Să se citească de la tastatură elementele unui vector cu n elemente numere întregi, să se calculeze
media geometrică a elementelor vectorului și să se afișeze pe monitor vectorul și valoarea mediei
geometrice. Funcția care citește vectorul de numere întregi trebuie să returneze un pointer (vezi model
funcție în curs). Vor trebui scrise următoarele funcții:
ü funcție pentru citirea unui vector de întregi cu n elemente. Funcția trebuie să aibă următorul
prototip:
int *pcitireVectorInt1(int n);
ü funcție pentru calculul mediei geometrice, cu prototipul:
double mediaGeometrica(int *x, int n);
Observație: Alocarea dinamică se va face de această dată în funcția pcitireVectorInt1.
Se va completa modulul (fișierul header și fișierul cu funcții proprii) de la problemele anterioare.

Problema nr. 2.4


Se citește de la tastatură un număr natural n și un vector de numere naturale v pentru care se face
alocare dinamică de memorie.

4
PROGRAMAREA CALCULATOARELOR ____________________________________________ Laborator Nr. 7

Se formează un nou vector w cu n elemente, de asemenea alocat dinamic, în care valoarea fiecărui
element este suma cifrelor valorii absolute a elementului corespunzător din vectorul v.
Să se afișeze elementul din vectorul v care are cea mai mare sumă a cifrelor sale.
Se vor scrie următoarele funcții:
ü Funcție pentru citirea unui vector de numere întregi care are ca parametru numărul de
elemente și returnează un pointer la întreg (vectorul citit).
ü Funcție pentru afișarea vectorului de numere întregi sub forma
A = (23, 543, 912)
Funcția are ca parametri vectorul de afișat (exprimat ca un pointer) și numărul de elemente.
ü Funcție pentru calculul sumei cifrelor unui număr natural. Funcția are ca parametru un număr
natural (numărul pentru care se calculează suma cifrelor) și returnează un număr natural (suma
calculată).
ü Funcție pentru determinarea elementelor vectorului w. Funcția are ca parametri un pointer și
un număr natural și returnează un pointer la un număr natural. Această funcție face apel, pentru
calculul sumei cifrelor unui număr natural, la funcția definită la punctul anterior.
ü Funcție pentru determinarea maximului dintr-un șir de numere. Funcția primește ca parametri
un pointer la un număr întreg și un întreg și returnează indexul elementului cu valoarea maximă.

Observație: Se va folosi același fișier header și același fișier cu funcții proprii ca la Problemele 2.1.-
2.3. (completate cu funcțiile pentru Problema 2.4)

TEMA 3
Problema nr. 3.1.
Să se scrie un program care:
- citește de la tastatură valorile elementelor unui vector (numere reale în dublă precizie). Vectorul este
stocat prin intermediul unui pointer.
- afișează vectorul citit sub forma
x = {2.13, -4.74, 0.25}
(se presupune că numele vectorului este X, iar numerele reale se vor afișa cu două zecimale și vor fi
separate de o virgulă și un spațiu).
- calculează pentru vectorul citit următoarele norme
‖𝑥‖! = max |𝑥$ | - norma infinit
"#$#%

‖𝑥‖" = |𝑥" | + |𝑥& | + ⋯ + |𝑥% | - norma 1

‖𝑥‖& = *|𝑥" |& + |𝑥& |& + ⋯ +|𝑥% |& - norma 2

Problema nr. 3.2


Să se scrie un program care pentru două mulțimi de numere reale
1. citește de la tastatură cardinalul și elementele fiecărei mulțimi
2. afișează cele două mulțimi sub forma
A = {3.14, 5.12, 3.00, 4.39}
B = {34.29, 15.14, 3.14}
(se presupune că numele celor două mulțimi sunt A și B, iar numerele reale se vor afișa cu două
zecimale și vor fi separate de o virgulă și un spațiu).

5
PROGRAMAREA CALCULATOARELOR ____________________________________________ Laborator Nr. 7

Observație (referitoare la punctele 1 și 2 ale Problemei 3.2):


Se scriu funcții pentru o singură mulțime. Funcțiile se apelează de mai multe ori. Funcțiile sunt cele
folosite la rezolvarea problemei 3.1 (se folosește același fișiere header și același fișier cu funcții ca la problema
3.1)

3. afișează un meniu care dă posibilitatea utilizatorului să aleagă una din următoarele prelucrări:
a) determinarea mulțimii intersecție a celor două mulțimi (A&B) și cardinalul acestei mulțimi.
b) determinarea mulțimii diferență simetrică a celor două mulțimi (A-B) (mulțimea diferență simetrică
include elementele mulțimii A care nu sunt în mulțimea B și elementele mulțimii B care nu sunt în mulțimea
A) și cardinalul acestei mulțimi.
c) determinarea mulțimii reuniune a celor două mulțimi (A+B) și cardinalul acestei mulțimi.
4. Realizează prelucrarea dorită și afișează mulțimea care rezultă în urma prelucrării.
Programul poate face o singură prelucrare în funcție de opțiunea utilizatorului și va trebui scris astfel
încât să permită prelucrarea mai multor seturi de date.
Observații:
1) Se va citi cu atenție tabelul următor care descrie în detaliu modul de rezolvare a problemei și
descrierea prototipurilor funcțiilor care trebuie scrise.
2) Dacă nu se folosesc funcțiile scrise codul nu se punctează.
3) Dacă nu se respectă indicațiile privind prototipurile punctajul este redus la jumătate.
4) Punctajul maxim se acordă pentru rezolvarea CORECTĂ a fiecărei subprobleme.
5) Dacă nu se folosesc funcții la rezolvare punctajul se reduce la jumătate.
6) Dacă sunt erori (chiar Warnings sau Segmentation Fault) punctajul este 1.

1. Alocarea corectă (cu verificare) de spațiu de memorie pentru pointerii corespunzători


1,0
mulțimilor inițiale
2. Citirea valorilor elementelor mulțimii (într-o funcție care primește ca parametru un număr
1,0
natural și returnează un pointer la real)
3. Afișarea valorilor vectorului din structură conform modelului dat în problemă 1,0
4. Scrierea meniului de prelucrare (funcția nu are nici un parametru și returnează un număr care
1,0
reprezintă numărul opțiunii de prelucrare)
5. posibilitatea de reluare a programului (prelucrarea mai multor seturi de date) 0,5
6. Folosire proiect (corect) 0,5
7. Fișier header (corect și complet) 0,5
8. Funcția main (complet – inclusiv eliberarea corectă a zonelor de memorie folosite) 1,0
9. Funcție care stabilește dacă o valoare aparține unei mulțimi. Funcția are 2 parametri: valoarea
și mulțimea (reprezentată prin structură) și returnează 1/0 după cum valoarea se găsește sau nu 0,5
în mulțime.
10. Calculul mulțimii intersecție – funcția returnează un pointer 1,0
11. Calculul mulțimii diferență simetrică – funcția returnează un pointer 1,0
12. Calculul mulțimii reuniune – funcția returnează un pointer 1,0
TOTAL 10 p

6
PROGRAMAREA CALCULATOARELOR ____________________________________________ Laborator Nr. 7

TEMA 4
Problema nr. 4.1
Se citește de la tastatură un număr întreg (poate fi pozitiv sau negativ). Numărul va fi memorat prin
intermediul unei variabile de tip int. Se determină numărul de cifre ale numărului (prin logaritmare în baza
10).
Se face alocare dinamică de memorie pentru un șir de caractere capabil să memoreze cifrele numărului
și eventualul semn. Numărul citit se transformă în șir de caractere, fără a folosi funcții de bibliotecă.
Transformarea se face astfel încât fiecare cifră să se plaseze direct pe locul ei.
Se afișează șirul de caractere rezultat (se folosește printf cu formatul %s).
Rezolvarea problemei presupune realizarea unui proiect care, pe lângă funcția main, să cuprindă și
funcții pentru:
ü transformarea numărului în șir de caractere. În acest caz funcția are prototipul:
char *transformareToAscii(long int);

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