De ce contează?
Imaginează-ți că pentru fiecare temă ții pe birou o foaie de ciornă. Pe ea mâzgălești calcule intermediare cât lucrezi la acea temă. Când termini, mototolești ciorna și o arunci la coș. Foaia există doar cât durează tema, iar colegul de la masa de alături nu vede nimic din ce-ai scris pe ea. O variabilă locală este exact această ciornă: apare când intri în funcție, te ajută la calcule și dispare în clipa în care funcția se termină.
Ce este
O variabilă locală este o variabilă declarată în interiorul unei funcții (sau al unui bloc { }). Ea are două proprietăți care merg mereu împreună:
- Domeniu de vizibilitate — locul din program de unde o poți folosi pe nume. Pentru o variabilă locală, acest loc este doar blocul în care a fost declarată. În afara funcției, numele ei pur și simplu nu există.
- Durată de viață — perioada cât variabila ocupă memorie. O locală se naște când execuția intră în funcție și e ștearsă când execuția iese din funcție.
De ce e util așa? Pentru că o funcție trebuie să fie o cutie închisă: îi dai date la intrare, îți întoarce un rezultat, dar calculele ei intermediare nu deranjează restul programului. Dacă fiecare funcție și-ar lăsa variabilele „la vedere”, două funcții care folosesc amândouă un i s-ar încurca una pe alta. Localitatea garantează că asta nu se întâmplă.
Reține perechea: domeniu de vizibilitate = de UNDE o vezi (doar funcția ei), durată de viață = CÂT timp trăiește (doar pe durata apelului). Din asta decurge totul: fiecare apel pornește cu locale proaspete, iar când apelul se încheie, ele dispar. Nimic nu „rămâne pe foaie” pentru data viitoare.
Cum arată
Privește acest program: funcția suma își declară o variabilă locală total, iar main are propriile variabile a, b, rezultat.
int suma(int x, int y) {
int total = x + y; // 'total' e LOCALA in 'suma'
return total;
}
int main() {
int a = 3, b = 5;
int rezultat = suma(a, b);
// aici 'total' NU exista: e invizibil in afara lui 'suma'
return 0;
}Fiecare nume „trăiește” într-o singură zonă. Diagrama arată cărui domeniu îi aparține fiecare variabilă — observă că total stă în coloana lui suma și nicăieri în main:
x | y | total | a | b | rezultat |
suma | suma | suma | main | main | main |
invizibil-in-main |
Parametrii x și y se comportă tot ca niște variabile locale: și ei apar la intrarea în funcție și dispar la ieșire. Singurul lucru care „iese” din suma este valoarea returnată prin return, copiată în rezultat — nu și variabila total în sine.
Implementare C++
Programul de mai jos arată trei idei dintr-o privire: o locală care nu se vede din main, două funcții care au fiecare propriul i fără să se ciocnească, și ce s-ar întâmpla dacă ai încerca să folosești o locală în afara funcției ei.
#include <iostream>
using namespace std;
int patrat(int n) {
int rezultat = n * n; // 'rezultat' e LOCALA in 'patrat'
return rezultat;
}
void numara() {
// acest 'i' e propriul lui 'i', separat de cel din 'afiseaza'
for (int i = 1; i <= 3; i++) {
cout << i << " ";
}
cout << endl;
}
void afiseaza() {
// acest 'i' NU are nicio legatura cu 'i' din 'numara'
for (int i = 10; i <= 12; i++) {
cout << i << " ";
}
cout << endl;
}
int main() {
cout << patrat(5) << endl; // 25
numara(); // 1 2 3
afiseaza(); // 10 11 12
// EROARE de compilare daca ai decomenta linia de mai jos:
// cout << rezultat; // 'rezultat' nu exista in main, e local in 'patrat'
return 0;
}Reține: cei doi i din numara și afiseaza poartă același nume, dar sunt variabile complet diferite — fiecare locală în propria funcție. Compilatorul le ține separat fără niciun efort din partea ta, exact pentru că sunt locale.
Trei capcane clasice cu variabilele locale:
- Returnezi adresa unei locale. Dacă o funcție întoarce un pointer sau o referință către o variabilă locală (de exemplu
return &total;), aceea trebuie să-ți dea de gândit: variabila e ștearsă în clipa în care funcția se termină, deci adresa primită indică spre memorie care nu-ți mai aparține. Returnează valoarea (return total;), nu adresa unei locale. - Aștepți ca o locală să rețină valoarea între apeluri. O locală obișnuită pornește din nou la fiecare apel. Dacă scrii
int contor = 0; contor++;într-o funcție,contorva fi mereu1după incrementare, oricâte ori chemi funcția — pentru că se naște din nou de fiecare dată. Vrei memorie între apeluri? Atunci ai nevoie de alt mecanism (un parametru, o valoare returnată), nu de o locală simplă. - Umbrești (shadowing) o variabilă din exterior. Dacă există o variabilă mai „de afară” cu numele
xși declari în funcție tot unxlocal, înăuntru vei folosi mereu pe cel local — cel exterior devine inaccesibil pe acel nume, deși încă există. Nu e o eroare de compilare, dar te poate păcăli să crezi că modifici una când de fapt o modifici pe cealaltă. Alege nume distincte când vrei să eviți confuzia.
Pentru contrast: opusul unei variabile locale este o variabilă globală — declarată în afara oricărei funcții, vizibilă de peste tot și care trăiește cât tot programul. Globalele rezolvă altă problemă (date comune mai multor funcții), dar pierd tocmai izolarea care face localele atât de sigure. Le studiezi separat, într-o lecție dedicată.