Saptamana 02 / 14 Programare Orientata Obiect
Recapitulare - pointeri si memorie dinamica
Pointeri si operatii pe pointeri, const si pointeri, vectori si matrice, citire si afisare cu cin si cout, new si delete, memory leaks si dangling pointers.
- Sa folosesti corect operatorii de adresa si de dereferentiere si nullptr
- Sa explici ce inseamna p + 1 si de ce p[i] este acelasi lucru cu *(p + i)
- Sa deosebesti pointerul la constanta, pointerul constant si pointerul constant la constanta
- Sa lucrezi cu vectori si matrice statice si sa le transmiti functiilor
- Sa aloci si sa eliberezi memorie cu new / delete si new[] / delete[]
- Sa recunosti un memory leak si un dangling pointer si sa spui cine detine un bloc de memorie
Pointeri: adresa si valoare
Un pointer este o variabila care retine o adresa. Doi operatori fac toata treaba:
&ada adresa luia;*pda valoarea aflata la adresa dinp.
int a = 5;
int* p = &a; // p retine adresa lui a
*p = 8; // scrie in a
int* q = nullptr; // nu arata nicaieri, intentionat
Un pointer care inca nu are unde sa arate trebuie sa fie nullptr. Nu il dereferentia niciodata: *q opreste programul.
Operatii pe pointeri
Daca aduni 1 la un pointer, el trece la elementul urmator, nu la octetul urmator. Compilatorul inmulteste singur cu dimensiunea tipului. De aceea p[i] si *(p + i) sunt acelasi lucru.
#include <iostream>
using namespace std;
int main() {
int v[5] = {10, 20, 30, 40, 50};
int* p = v;
p += 2;
cout << *p << " " << *(p + 1) << " " << p[-1] << endl;
cout << p - v;
} Diferenta a doi pointeri in acelasi vector este numarul de elemente dintre ei. Sa compari sau sa scazi pointeri din vectori diferiti nu are sens.
const si pointeri
Citeste declaratia de la dreapta la stanga. const se aplica la ce este imediat in stanga lui (sau in dreapta, daca e primul).
| Declaratie | Modifici *p? | Modifici p? |
|---|---|---|
const int* p (pointer la constanta) | Nu | Da |
int* const p (pointer constant) | Da | Nu |
const int* const p | Nu | Nu |
int a = 1, b = 2;
const int* p1 = &a; p1 = &b; // OK *p1 = 3; // eroare
int* const p2 = &a; *p2 = 5; // OK p2 = &b; // eroare
const int* const p3 = &a; // *p3 = 3; si p3 = &b; sunt ambele erori
Vectori si matrice
Numele unui vector static se comporta ca un pointer constant la primul element: v[i] merge, v = alt_vector nu compileaza. Cand transmiti un vector unei functii, se copiaza doar adresa, deci dimensiunea trebuie trimisa separat:
int suma(const int v[], int n); // la fel ca const int* v
O matrice int m[2][3] este memorata linie cu linie, ca 6 intregi consecutivi.
#include <iostream>
using namespace std;
int main() {
int m[2][3] = {{1, 2, 3}, {4, 5, 6}};
int s = 0;
for (int i = 0; i < 2; i++) s += m[i][2];
cout << s << " " << m[1][0];
} cin, cout si new[]
Cand dimensiunea se afla abia la executie, aloca pe heap cu new[] si elibereaza cu delete[]. Ruleaza, apoi incearca alte date de intrare.
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int* v = new int[n];
for (int i = 0; i < n; i++) cin >> v[i];
int s = 0;
for (int i = 0; i < n; i++) s += v[i];
cout << "suma: " << s << endl; // asteptat pentru 4 7 9 10 6: suma: 32
delete[] v;
v = nullptr;
}Intrare (stdin)
new / delete si new[] / delete[]
Fiecare alocare are exact o eliberare pereche:
| Alocare | Eliberare |
|---|---|
new int(7) | delete p; |
new int[n] | delete[] p; |
malloc(...) | free(p); |
Daca le amesteci (delete pe un bloc new[], free pe un bloc new), ai comportament nedefinit. La fel daca eliberezi acelasi bloc de doua ori.
int* v = new int[3]{7, 9, 10}; - v este pe stiva, cei trei intregi sunt pe heap.
Pasul 1/3
Memory leaks
Un leak este un bloc de pe heap a carui adresa nu o mai ai. Nimeni nu il mai poate elibera.
int* p = new int[10];
p = new int[10]; // primul bloc s-a pierdut: leak
void f() {
int* t = new int[3];
} // t dispare, blocul ramane: leak
Inainte sa scrii new, hotaraste cine detine blocul, adica cine va apela delete. Daca o functie intoarce un pointer la memorie noua, apelantul o detine, iar comentariul de deasupra functiei trebuie sa spuna asta.
Dangling pointers
Un dangling pointer retine o adresa la care nu mai exista un obiect valid. Doua moduri obisnuite de a obtine unul:
int* creeazaValoare() {
int valoare = 10;
return &valoare; // gresit: valoare dispare la iesirea din functie
}
int* p = new int(5);
delete p;
*p = 6; // gresit: blocul a fost eliberat
g++ te avertizeaza pentru primul caz (address of local variable returned). Citirea printr-un dangling pointer este comportament nedefinit: poate afisa vechea valoare, gunoi, sau programul se poate opri.
Verifica-te
Scor: 0/7