Historia pytania:
Pamięć stosu występuje we wszystkich głównych architekturach. W języku C zmienne automatyczne (lokalne) są umieszczane na stosie, co zapewnia dużą szybkość przydzielania i zwalniania pamięci w porównaniu do dynamicznego sterty.
Problem:
Użycie stosu jest ograniczone pod względem rozmiaru, zmienne automatyczne są automatycznie niszczone po wyjściu z bloku, a przekroczenie granic stosu (stack overflow) prowadzi do awaryjnego zakończenia programu lub uszkodzenia danych.
Rozwiązanie:
Lokalne zmienne zadeklarowane wewnątrz funkcji bez specjalnego modyfikatora są umieszczane na stosie. Ta przestrzeń automatycznego przechowywania jest tworzona przy wejściu do funkcji i niszczona po wyjściu. Rozmiar stosu jest ograniczony i można go zmieniać jedynie za pomocą opcji linkera/systemu.
Przykład kodu:
#include <stdio.h> void foo() { int arr[100]; // umieszczone na stosie for (int i = 0; i < 100; ++i) arr[i] = i; printf("Pierwszy element: %d\n", arr[0]); } // arr jest niszczone po wyjściu z foo
Kluczowe cechy:
Czy można zwrócić lokalną zmienną z funkcji przez adres?
Nie, ponieważ zmienna jest niszczona po wyjściu z funkcji, a uzyskany "wiszący wskaźnik" prowadzi do nieokreślonego zachowania.
int* bad() { int x = 42; return &x; // błąd: zwrócony wskaźnik wskazuje na zwolniony stos }
Czy można umieścić dużą tablicę (np. 1 MB) na stosie?
Dla większości systemów stos jest ograniczony (od dziesiątek do setek KB). Próbując zadeklarować ogromne tablice na stosie, doprowadzi to do stack overflow.
Jaka jest różnica między zmiennymi static a automatycznymi przy alokacji?
Zmiennie static (nawet w funkcji) są umieszczane w statycznym obszarze pamięci, nie są czyszczone między wywołaniami, podczas gdy zmienne automatyczne są umieszczane na stosie i są niszczone po wyjściu z bloku.
W funkcji do obliczeń przydzielano tablicę 8192*1024 double na stosie. Program otrzymywał SIGSEGV przy uruchomieniu w Linuxie, chociaż kompilował się bez błędów.
Zalety:
Wady:
Do pracy z dużymi buforami używano dynamicznego przydzielania pamięci przez malloc/free. Na stosie umieszczano tylko małe zmienne robocze.
Zalety:
Wady: