Sari la conținut
EduCamp

Tematică științifică · 4.2

Operațiile de alocare și eliberare

Tipul pointer și tipul referință în C++, operatorii pentru pointeri, definirea tipurilor de date, alocarea cu new pentru date simple, înregistrări și tablouri, accesarea datelor alocate dinamic și eliberarea memoriei cu delete.

În C++, datele alocate dinamic se prelucrează cu ajutorul pointerilor. Un program care folosește alocarea dinamică definește tipurile de date necesare, alocă memorie pentru date, le accesează prin adresele lor și eliberează memoria în momentul în care datele nu mai sunt necesare.

Tipul pointer

Un pointer este o variabilă care memorează adresa unei zone de memorie. Declararea unui pointer are forma generală:

tip *nume_pointer;

tip se numește tipul de bază al pointerului și este tipul datei aflate la adresa memorată. Adresa arată numai primul octet al zonei. Din tipul de bază, compilatorul află câți octeți ocupă data și cum trebuie interpretat conținutul lor: în 4 octeți se poate păstra la fel de bine un int sau un float, iar aceeași secvență de biți are valori diferite în cele două cazuri.

Pointerul p poate păstra numai adresa unei date de tip int, r numai adresa unei date de tip double, iar a numai adresa unei înregistrări de tip punct.

int *p;
double *r;

struct punct {
    int x, y;
};
punct *a;

Constanta NULL. Valoarea NULL, egală cu 0, arată că pointerul nu memorează adresa niciunei date. Ea se folosește la inițializarea pointerilor și la marcarea sfârșitului unei structuri de date înlănțuite, iar testul p == NULL arată dacă pointerul indică o dată.

Pointerul neinițializat. Un pointer local căruia nu i s-a atribuit nicio valoare conține o valoare reziduală, adică o adresă oarecare. Scrierea la această adresă produce de obicei o eroare la execuție sau modifică, fără niciun semnal, alte date ale programului.

Operatorii pentru pointeri

Referențierea și dereferențierea

Operatorul & furnizează adresa unei variabile, iar operatorul * furnizează data aflată la adresa memorată într-un pointer.

OperatorulOperațiaSe aplică peRezultatul
&referențiereao variabilă sau un element de tablouadresa acestora, de tip pointer
*dereferențiereaun pointerdata de la adresa memorată, de tipul de bază al pointerului

Expresia *p se poate folosi oriunde se poate folosi o variabilă de tipul de bază: într-o expresie, în membrul stâng al unei atribuiri sau la citire, în cin >> *p.

Instrucțiunile a = 15; și *p = 15; au același efect cât timp p memorează adresa lui a. Prima folosește adresarea directă, prin nume, iar a doua adresarea indirectă, prin adresă.

int a = 10, b = 20;
int *p = &a;     // p memoreaza adresa lui a

cout << *p;      // 10, valoarea lui a
*p = 15;         // se modifica a
cout << a;       // 15
b = *p + 1;      // b primeste 16
p = &b;          // acum p indica variabila b
cout << *p;      // 16

Accesul la câmpurile unei înregistrări

Dacă a este un pointer către o înregistrare, *a este înregistrarea, iar un câmp al ei se scrie (*a).x. Parantezele sunt necesare, fiindcă operatorul . are prioritate mai mare decât operatorul *: fără ele, *a.x s-ar citi *(a.x) și ar produce o eroare de compilare.

Aceeași operație se scrie mai simplu cu operatorul ->, numit operatorul de selecție indirectă: a->x este echivalent cu (*a).x.

Prin a->x și a->y se ajunge la câmpurile înregistrării m, a cărei adresă este memorată în a.

punct m = {3, 4};
punct *a = &m;

cout << (*a).x << " " << (*a).y;   // 3 4
cout << a->x << " " << a->y;       // 3 4

Atribuirea

Unui pointer i se poate atribui:

  • adresa unei variabile de tipul de bază, p = &a;;
  • valoarea altui pointer cu același tip de bază, q = p;, după care cei doi pointeri indică aceeași zonă de memorie;
  • numele unui tablou cu elemente de tipul de bază, p = v;, echivalent cu p = &v[0];;
  • constanta NULL;
  • adresa furnizată de operatorul new.

Numele unui tablou este o constantă de tip adresă: el are ca valoare adresa primului element și nu poate fi modificat. De aceea atribuirile v = p; și v = w;, cu v și w tablouri, produc erori de compilare.

Operațiile aritmetice

Asupra pointerilor se pot efectua adunarea și scăderea unui număr întreg, incrementarea, decrementarea și scăderea a doi pointeri cu același tip de bază. Unitatea în care se calculează este sizeof(tip), adică lungimea unei date de tipul de bază.

ExpresiaRezultatul
p + kadresa aflată cu k elemente după p, adică adresa din p plus k · sizeof(tip)
p - kadresa aflată cu k elemente înaintea lui p
p++, p--pointerul trece la elementul următor, respectiv la cel precedent
q - pnumărul de elemente dintre cele două adrese

Operațiile aritmetice au sens numai dacă pointerii indică elemente ale aceluiași tablou. În afara unui tablou, la adresa obținută nu se află o dată a programului.

Legătura dintre pointeri și tablouri decurge din aceste reguli. Dacă v este un tablou, v + i este adresa elementului v[i], iar *(v + i) este chiar elementul v[i]. Un tablou se poate parcurge cu un pointer q, care pornește de la v și se oprește la v + n.

int v[5] = {10, 20, 30, 40, 50};

cout << *(v + 2);       // 30, adica v[2]

for (int *q = v; q < v + 5; q++)
    cout << *q << " ";  // 10 20 30 40 50

Operatorii relaționali

Operatorii == și != arată dacă doi pointeri memorează aceeași adresă și se folosesc mai ales în comparația cu NULL. Operatorii <, <=, > și >= au sens pentru pointeri care indică elemente ale aceluiași tablou: p < q înseamnă că elementul indicat de p se află înaintea celui indicat de q.

Tipul referință

O referință este un al doilea nume pentru o variabilă existentă. Referința și variabila desemnează aceeași zonă de memorie, deci orice modificare făcută prin unul dintre nume se vede și prin celălalt.

tip &nume_referinta = variabila;

Referința se supune regulilor următoare:

  • se inițializează obligatoriu la declarare;
  • după inițializare, nu mai poate fi legată de altă variabilă: b = c; copiază valoarea lui c în a;
  • are același tip ca variabila la care se referă.
int a = 10, c = 3;
int &b = a;      // b este un alt nume pentru a

b = 25;
cout << a;       // 25
b = c;           // a primeste valoarea 3
cout << a;       // 3

Tipul referință se folosește la transmiterea parametrilor prin referință, prezentată în subcapitolul Subprograme definite de utilizator. La alocarea dinamică se transmite frecvent prin referință chiar un pointer, cu parametrul scris tip *&p. Subprogramul poate modifica atunci adresa memorată în pointerul din modulul apelant, ceea ce se întâmplă la orice alocare făcută într-un subprogram.

Parametrul p este o referință la pointerul q din main. Adresa rezervată de new ajunge astfel în q.

Fără &, subprogramul ar lucra cu o copie a lui q. La revenire, q ar avea tot valoarea NULL, iar adresa zonei alocate s-ar pierde odată cu copia.

void aloca(int *&p, int x) {
    p = new int;
    *p = x;
}

int main() {
    int *q = NULL;
    aloca(q, 7);
    cout << *q;      // 7
    delete q;
    return 0;
}

Materialul acesta se citește pe educamp.ro și nu se tipărește.

Ce cuprinde subcapitolul

  1. Tipul pointer
  2. Operatorii pentru pointeri
  3. Tipul referință
  4. Definirea tipurilor de date necesare
  5. Alocarea memoriei
  6. Accesarea datelor alocate dinamic
  7. Eliberarea memoriei
  8. Greșeli frecvente
  9. Apariții la examen

Continuă lectura ca și cursant

Cel puțin un subcapitol din fiecare capitol este disponibil gratuit și integral. Pentru a citi toate celelalte subcapitole ale disciplinei, te înscrii la cursul de pregătire.

Prima săptămână este gratuită, fără plată și fără card. Dacă vrei să vezi mai întâi cum este prezentată materia, poți reveni la primul subcapitol al capitolului.

100 RON / lună, pentru o disciplină

Ce cuprinde:

  • Două întâlniri de câte două ore, în fiecare lună
  • Tot suportul de curs publicat până acum la disciplina aleasă
  • Capitole noi în fiecare săptămână, cuprinse în luna plătită, fără costuri suplimentare
  • Material organizat după structura programei de examen
  • Acces de pe orice dispozitiv, folosind același cont
  • Prima săptămână gratuită, fără card și fără reînnoire automată

Începe săptămâna gratuită Sunt cursant — login

Află când publicăm materiale noi

Materia este publicată treptat, capitol cu capitol. Înscrie-te pentru a primi un e-mail atunci când apare un capitol nou de informatică.

Vei primi mesaje numai despre materia selectată și despre cursul de pregătire. Te poți dezabona oricând, dintr-o singură apăsare.

Surse

  • Cerchez, E., Șerban, M., „Programarea în limbajul C/C++ pentru liceu”, Editura Polirom, Iași, 2005
  • „Informatică. Manual pentru clasa a XI-a”, Editura Didactică și Pedagogică, București
  • Programa pentru examenul de definitivare în învățământ, disciplina Informatică, cap. 4 „Alocarea dinamică a memoriei”
  • Programa pentru concursul de ocupare a posturilor didactice, disciplina Informatică, cap. 4 „Alocarea dinamică a memoriei”
  • Subiecte și bareme publicate, Titularizare, informatică, 2009, 2017, 2018, 2021
Actualizat: 12 septembrie 2026