Pointeri
Un pointer este o variabilă care stochează adresa altei variabile din memorie.
Până acum, variabilele noastre stocau valori:
int x = 5 înseamnă “x conține valoarea 5”. Un
pointer nu conține o valoare, ci locul în
memorie unde se află acea valoare.
De ce avem nevoie de pointeri?
- Pentru a înțelege cum funcționează șirurile de caractere și vectorii în C++
- Pentru a transmite date la funcții eficient (fără a copia totul)
- Pentru a lucra cu memorie dinamică (alocare la rulare)
- Sunt baza multor structuri de date avansate (liste, arbori, grafuri)
Adresa unei variabile
Fiecare variabilă din program ocupă un loc în memorie. Acel loc are o adresă - un număr care identifică poziția.
Operatorul & ne dă adresa
unei variabile:
#include <iostream>
using namespace std;
int main()
{
int x = 42;
cout << "Valoarea: " << x << endl;
cout << "Adresa: " << &x << endl;
return 0;
}Output:
Valoarea: 42
Adresa: 0x7ffd5c3e4a8cAdresa este un număr hexazecimal (începe cu 0x).
Nu contează valoarea exactă - important este
conceptul: fiecare variabilă are o adresă
unică.
Declararea unui pointer
Un pointer se declară cu * după
tipul de date:
int *p; // p este un pointer către un int
char *s; // s este un pointer către un char
double *d; // d este un pointer către un doubleint *p se citește: “p este un pointer care
pointează (arată) către o valoare de tip
int”.
Legarea unui pointer de o variabilă
Folosim & pentru a obține adresa și o
atribuim pointerului:
int x = 42;
int *p = &x; // p pointează către xAcum p conține adresa lui x.
Memorie:
x: [ 42 ] adresa: 1000
p: [ 1000 ] adresa: 2000
↓
x
Dereferențierea - accesarea valorii
Operatorul * aplicat pe un
pointer ne dă valoarea de la adresa
respectivă:
int x = 42;
int *p = &x;
cout << p; // afișează adresa (ex: 0x7ffd...)
cout << *p; // afișează 42 (valoarea lui x)
*pse citește: “valoarea de la adresa pe care o conține p” sau mai simplu “valoarea pe care o indică p”.
Modificarea prin pointer
Putem modifica variabila originală prin pointer:
int x = 42;
int *p = &x;
*p = 100; // modificăm valoarea de la adresa lui p
cout << x; // afișează 100 (x s-a schimbat!)Asta funcționează pentru că p și x
se referă la aceeași locație din memorie.
Exemplu complet pas cu pas
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 20;
int *p;
p = &a; // p arată către a
cout << *p; // 10
*p = 15; // a devine 15
cout << a; // 15
p = &b; // p arată acum către b
cout << *p; // 20
*p = *p + 5; // b devine 25
cout << b; // 25
return 0;
}| Linie | p arată către | *p | a | b |
|---|---|---|---|---|
p = &a |
a | 10 | 10 | 20 |
*p = 15 |
a | 15 | 15 | 20 |
p = &b |
b | 20 | 15 | 20 |
*p = *p + 5 |
b | 25 | 15 | 25 |
Pointeri și vectori
Numele unui vector este de fapt un pointer către primul element:
int v[5] = {3, 7, 2, 9, 4};
cout << v; // adresa primului element
cout << *v; // 3 (valoarea primului element)
cout << v[0]; // 3 (echivalent cu *v)Aritmetica pe pointeri
Dacă p pointează către un element al vectorului,
p + 1 pointează către următorul
element:
int v[5] = {3, 7, 2, 9, 4};
int *p = v; // p arată către v[0]
cout << *p; // 3 (v[0])
cout << *(p + 1); // 7 (v[1])
cout << *(p + 2); // 2 (v[2])
cout << *(p + 3); // 9 (v[3])
v[i]este echivalent cu*(v + i)
Aceasta este legătura fundamentală între vectori și pointeri în C++.
p p+1 p+2 p+3 p+4
↓ ↓ ↓ ↓ ↓
[ 3 ] [ 7 ] [ 2 ] [ 9 ] [ 4 ]
v[0] v[1] v[2] v[3] v[4]
Pointeri și șiruri de caractere
Un șir de caractere char s[] = "Salut" este un
vector de char. Deci s este un pointer
către primul caracter:
char s[] = "Salut";
char *p = s; // p arată către 'S'
cout << *p; // S
cout << *(p + 1); // a
cout << *(p + 2); // lParcurgerea unui șir cu pointer
char s[] = "Algoritm";
char *p = s;
while (*p != '\0') {
cout << *p;
p++;
}La fiecare pas, p avansează la următorul
caracter. Când ajunge la '\0', bucla se
oprește.
Aceasta este exact ceea ce face
for (int i = 0; s[i] != '\0'; i++) - dar cu pointer
în loc de indice.
Pointer nul
Un pointer care nu arată către nimic se inițializează cu
NULL sau nullptr:
int *p = NULL; // stilul C
int *p = nullptr; // stilul C++ modern (recomandat)Nu accesați niciodată
*pdacăpeste nul - programul se oprește cu eroare.
int *p = nullptr;
if (p != nullptr) {
cout << *p; // sigur, p pointează către ceva
}Transmiterea prin referință (pointer)
Dacă vrem ca o funcție să modifice o variabilă, îi transmitem adresa:
#include <iostream>
using namespace std;
void dubleaza(int *p) {
*p = *p * 2;
}
int main()
{
int x = 5;
dubleaza(&x); // transmitem adresa lui x
cout << x; // 10 (x s-a modificat)
return 0;
}Fără pointer, funcția ar lucra pe o copie și
x ar rămâne 5.
Transmitere prin valoare vs pointer
Prin valoare: funcția primește o copie. Modificările nu afectează originalul.
void f(int a) {
a = 100; // modifică doar copia
}Prin pointer: funcția primește adresa. Modificările afectează originalul.
void f(int *p) {
*p = 100; // modifică valoarea originală
}C++ oferă și referințe
(int &a) care fac același lucru mai elegant,
dar pointerii sunt baza pe care se construiesc referințele.
Rezumat operatori
| Operator | Semnificație | Exemplu |
|---|---|---|
&x |
Adresa lui x | int *p = &x; |
*p |
Valoarea de la adresa p | cout << *p; |
int *p |
Declarare pointer | int *p = &x; |
p + 1 |
Următoarea adresă | *(p + 1) = elementul următor |
p++ |
Avansează pointerul | Trece la elementul următor |
Greșeli frecvente
1. Utilizarea unui pointer neinițializat
int *p;
*p = 5; // GREȘIT! p nu arată către nimic validUn pointer trebuie mereu inițializat cu
adresa unei variabile sau cu nullptr.
2. Confuzia
între * la declarare și * la
utilizare
int *p = &x; // * aici înseamnă "p este pointer"
*p = 10; // * aici înseamnă "valoarea de la adresa p"Aceeași notație, două semnificații diferite:
- La declarare: indică tipul (pointer)
- La utilizare: dereferențiere (accesare valoare)
3. Dereferențierea unui pointer nul
int *p = nullptr;
cout << *p; // EROARE! Programul se opreșteVerifică mereu dacă pointerul nu este nul înainte de a-l accesa.
4. Confuzia între adresă și valoare
int x = 5;
int *p = &x;
cout << p; // afișează adresa (un număr mare hexazecimal)
cout << *p; // afișează 5 (valoarea)Ce să reții
- Un pointer stochează adresa unei variabile, nu o valoare.
&xdă adresa lui x,*pdă valoarea de la adresa p.- Numele unui vector este un pointer către primul element.
v[i]este echivalent cu*(v + i).- Pointerii permit modificarea variabilelor din funcții.
- Un pointer neinițializat sau nul nu trebuie dereferențiat.
- Pointerii sunt baza pe care funcționează șirurile de caractere, vectorii și structurile de date avansate.