Zasięg (scope) i czas życia (lifetime) zmiennych to jedne z kluczowych aspektów struktury programu w C. Zasięg to część kodu, w której zmienna jest dostępna po nazwie. Czas życia określa, kiedy zmienna rzeczywiście istnieje w pamięci.
Historia problemu
C został zaprojektowany z myślą o niskopoziomowej kontroli, dlatego zapewnia elastyczne, ale niebezpieczne podejście do zasięgu i czasów życia poprzez klasyfikację zmiennych według miejsca deklaracji (blokowa, plikowa, globalna, statyczna).
Problem
Niewłaściwe zrozumienie zasięgu/czasu życia prowadzi do klasycznych błędów: próba dostępu do niedostępnych lub już zniszczonych zmiennych (use-after-free), konflikt nazw między zmiennymi globalnymi a lokalnymi (cienie zmiennych), niezamierzone zmiany zmiennych globalnych.
Rozwiązanie
Jawnie określać potrzebny typ przechowywania (auto, static, extern), rozsądnie używać blokowego zasięgu, minimalizować liczbę zmiennych globalnych, wyraźnie rozróżniać czas życia na stosie i poza stosem.
Przykład kodu:
int global_var; // Globalna, żyje przez cały czas wykonania void func() { int local_var = 5; // Automatyczna, żyje w zakresie func() static int stat_var = 0; // Statyczna, żyje między wywołaniami stat_var++; }
Kluczowe cechy:
Co się stanie, jeśli zadeklarujesz dwie zmienne o tej samej nazwie w różnych blokach?
Wewnętrzna zmienna ukryje zewnętrzną (zmienna cień). Może to prowadzić do nieoczekiwanych błędów.
int x = 10; ... if (1) { int x = 50; printf("%d", x); // drukuje 50, globalny x jest ukryty }
Jaki czas życia ma automatyczna zmienna zadeklarowana wewnątrz funkcji?
Istnieje tylko w czasie wywołania funkcji. Po wyjściu pamięć jest zwalniana, a wartość ginie.
Czy statyczna lokalna zmienna może być użyta poza funkcją, w której została zadeklarowana?
Nie, zasięg ma tylko wewnątrz funkcji. Jest niewidoczna na zewnątrz, mimo że czas życia trwa przez cały czas wykonania programu.
void f() { static int x = 0; } // Niedostępna poza f()
static vs auto).Początkujący programista tworzy licznik wewnątrz pętli jako static, a ten licznik "zapisuje" wartości między iteracjami, chociaż oczekiwano zera za każdym razem.
Zalety:
Wady:
Programista używa static wyłącznie do buforowania, a do tymczasowych potrzeb — zwykłych zmiennych auto.
Zalety:
Wady: