Programare Competitivă

Variabile locale și globale

Când scriem funcții, o întrebare importantă este: unde există o variabilă? Poate fi accesată din orice funcție sau doar din cea în care a fost declarată?


Variabile locale

O variabilă declarată în interiorul unei funcții este locală. Ea există doar cât timp funcția se execută și nu poate fi accesată din altă parte.

#include <iostream>
using namespace std;

void functie() {
    int x = 10;
    cout << x << endl;
}

int main()
{
    functie();
    // cout << x;  // EROARE! x nu există aici

    return 0;
}

x este locală funcției functie(). În main nu știm de ea.

Fiecare funcție are propriile variabile

void f1() {
    int a = 5;
    cout << a << endl;
}

void f2() {
    int a = 100;
    cout << a << endl;
}

int main()
{
    f1();
    f2();
    return 0;
}
Output:
5
100

Variabila a din f1 și a din f2 sunt complet diferite - au doar același nume. Fiecare funcție are propriul spațiu.


Variabile globale

O variabilă declarată în afara tuturor funcțiilor este globală. Ea poate fi accesată din orice funcție.

#include <iostream>
using namespace std;

int contor = 0;   // globală

void incrementeaza() {
    contor++;
}

int main()
{
    incrementeaza();
    incrementeaza();
    incrementeaza();
    cout << contor << endl;

    return 0;
}
Output:
3

contor este globală - ambele funcții (incrementeaza și main) o văd și o pot modifica.


Diferențe cheie

Locale Globale
Unde se declară În interiorul unei funcții În afara tuturor funcțiilor
Cine le vede Doar funcția respectivă Toate funcțiile
Durata de viață Cât se execută funcția Tot programul
Valoare inițială Nedefinită (gunoi) Automat 0
Bune pentru Calcule temporare Vectori, fin/fout, date partajate

Foarte important: variabilele locale nu sunt inițializate automat. Dacă nu le dai o valoare, conțin “gunoi”. Variabilele globale sunt automat 0.


Suprapunerea numelor

Dacă o variabilă locală are același nume cu una globală, cea locală o “ascunde” pe cea globală.

#include <iostream>
using namespace std;

int x = 100;    // globală

void functie() {
    int x = 5;  // locală - ascunde globala
    cout << "In functie: " << x << endl;
}

int main()
{
    cout << "Inainte: " << x << endl;
    functie();
    cout << "Dupa: " << x << endl;

    return 0;
}
Output:
Inainte: 100
In functie: 5
Dupa: 100

În functie(), x se referă la variabila locală (5). Globala (100) nu e afectată.

De ce se întâmplă asta?

Compilatorul caută mai întâi o variabilă locală cu acel nume. Dacă o găsește, o folosește pe ea. Doar dacă nu există local, caută global.

De aceea, este o practică bună să nu folosim același nume pentru variabile locale și globale - evităm confuzii.


Când folosim variabile globale?

La concursuri, declarăm global:

  • Vectorii (sunt mari și nu încap pe stivă)
  • fin și fout (accesibile din orice funcție)
  • n (dimensiunea vectorului - folosit peste tot)
#include <fstream>
using namespace std;
ifstream fin("date.in");
ofstream fout("date.out");

int v[100001];     // global - vector mare
int n;             // global - dimensiune

void citeste() {
    fin >> n;
    for (int i = 1; i <= n; i++)
        fin >> v[i];
}

void afiseaza() {
    for (int i = 1; i <= n; i++)
        fout << v[i] << " ";
}

int main()
{
    citeste();
    afiseaza();
    return 0;
}

Variabile locale în bucle

Variabilele declarate într-o buclă for sunt locale buclei:

for (int i = 1; i <= 5; i++) {
    cout << i;
}
// cout << i;  // EROARE! i nu mai există aici

La fel în if sau while:

if (n > 0) {
    int temp = n * 2;
    cout << temp;
}
// cout << temp;  // EROARE! temp nu mai există

Parametrii sunt variabile locale

Parametrii unei funcții se comportă ca variabile locale:

int dublu(int x) {
    x = x * 2;    // modificăm variabila locală x (copia)
    return x;
}

int main()
{
    int a = 5;
    cout << dublu(a);  // 10
    cout << a;         // 5 - neschimbat
    return 0;
}

x este locală funcției dublu - este o copie a lui a.


Exemplu: de ce contează

#include <iostream>
using namespace std;

int suma = 0;   // globală

void adauga(int x) {
    int suma = 0;   // locală! Ascunde globala!
    suma = suma + x;
    cout << "Local: " << suma << endl;
}

int main()
{
    adauga(5);
    adauga(3);
    cout << "Global: " << suma << endl;

    return 0;
}
Output:
Local: 5
Local: 3
Global: 0

adauga modifică variabila locală suma, nu pe cea globală. Globala rămâne 0. Dacă ștergem int din fața lui suma din funcție, ar folosi globala.


Greșeli frecvente

1. Variabila locală neinițializată

void f() {
    int x;
    cout << x;   // valoare aleatorie (gunoi)!
}

Variabilele locale trebuie inițializate explicit.


2. Aceeași denumire - confuzie

int n = 10;       // globală

void f() {
    int n = 5;    // locală - ascunde globala
    // credem că modificăm globala, dar nu
}

Evită să dai același nume variabilelor locale și globale.


3. Vector declarat local

void f() {
    int v[100000];  // PERICOL! Poate depăși stiva
}

Vectorii mari trebuie declarați global.


Ce să reții

  • Locale - declarate în funcție, vizibile doar acolo, neinițializate automat.
  • Globale - declarate în afara funcțiilor, vizibile peste tot, inițializate cu 0.
  • O variabilă locală cu același nume ascunde globala.
  • Parametrii funcțiilor sunt variabile locale (copii).
  • La concursuri: vectori, fin/fout și n se declară global.
  • Variabilele locale declarate în bucle sau blocuri if există doar în acel bloc.