[ Pobierz całość w formacie PDF ]

tworzenia i niszczenia w zależności od potrzeb. Wymaga to co prawda użycia spec-
jalnych procedur, pozwala jednak na znacznie bardziej efektywną gospodarkę pamięcią.
W odróżnieniu od statycznych zmiennych globalnych, istniejących przez cały czas
wykonywania programu, zmienne wskazywane należą do klasy zmiennych dynamicz-
nych (czyli istnieją dokładnie wtedy, gdy życzy sobie tego programista). Sam proces
utworzenia zmiennej dynamicznej polega na zarezerwowaniu odpowiedniego obszaru
pamięci i zapamiętaniu adresu tego obszaru we wskazniku wskazującym na zmienną.
Z kolei usunięcie zmiennej powoduje  zwolnienie rezerwacji (zawartości zmiennej
oraz wskaznika nie są fizycznie niszczone, ale lepiej się już do nich nie odwoływać).
Ceną za możliwość swobodnego przydzielania i zwalniania pamięci jest konieczność
bezwzględnego inicjalizowania wskazników, które przed utworzeniem wskazywanej
zmiennej mają wartość nieokreśloną (zwykle zero, co odpowiada wskaznikowi nil, nie
wskazującemu na żaden obiekt). Próba odczytu zmiennej wskazywanej przez taki wska-
znik dostarczy  tylko bezsensownego wyniku, natomiast próba zapisu (w
przypadkowe miejsce pamięci!!) może skończyć się zawieszeniem komputera lub
zupełnie nieprzewidzianym jego zachowaniem.
Pamiętaj o inicjalizacji wskazników!
Więcej pamięci! 117
Turbo Pascal oferuje kilka metod tworzenia i usuwania zmiennych dynamicznych,
z których najpopularniejszą realizuje para procedur new i dispose:
-do-zmiennej)
-do-zmiennej)
Procedura new wykonuje czynności związane z utworzeniem zmiennej wskazywanej,
natomiast dispose  operacje związane z jej usunięciem. Drugą parę zarządzającą
dynamicznym przydziałem pamięci tworzą procedury GetMem i FreeMem:
-bloku)
-bloku)
W odróżnieniu od pary new-dispose, procedury te wykorzystują wskazniki
amorficzne (typu pointer) i służą do bardziej  wewnętrznego manipulowania
pamięcią, tj. przydzielania i zwalniania bloków bajtów (a nie zmiennych wskazywanych
jakiegoś konkretnego typu). Wielkość przydzielanego lub zwalnianego bloku (w
bajtach) określa parametr rozmiar-bloku. Korzystając z obu grup procedur musisz
pamiętać, że pamięć przydzielona przez GetMem nie może być zwolniona procedurą
dispose i odwrotnie.
Ostatnią, chyba najrzadziej stosowaną parę tworzą procedury mark i release:
Wykonanie procedury mark nie powoduje przydzielenia pamięci ani utworzenia zmien-
nej, a jedynie zapamiętanie bieżącej  wysokości sterty w zmiennej . Zwol-
nienia całego obszaru sterty leżącego powyżej dokonuje się za pomocą
procedury release. Obydwie procedury stosowane są  podobnie jak GetMem
i FreeMem  głównie w programowaniu niskiego poziomu, do  masowego
zwalniania pamięci przydzielonej na stercie.
Korzystając ze zmiennych dynamicznych musisz pamiętać, że sterta nie jest automa-
tycznie porządkowana, toteż kolejne operacje przydzielenia i zwolnienia bloków pamię-
ci (dowolną metodą) mogą doprowadzić do tzw. fragmentacji, czyli rozbicia wolnego
jeszcze obszaru pamięci na mniejsze, rozłączne bloki. Ponieważ rozmiar tworzonej
zmiennej dynamicznej nie może być większy od rozmiaru największego wolnego bloku
pamięci, może się okazać, że próba utworzenia zmiennej skończy się niepowodzeniem,
mimo iż wielkość dostępnej pamięci będzie wystarczająca. Dlatego też właściwą miarą
możliwości utworzenia większej struktury danych na stercie jest nie funkcja MemAvail
(zwracająca sumaryczny rozmiar wolnej pamięci), lecz MaxAvail (zwracająca rozmiar
największego wolnego bloku).
Pora na przykłady. Na początek przedstawimy  zbiorczą demonstrację możliwości ob-
sługi zmiennych dynamicznych.
program ZmienneDynamiczne;
type
118 Turbo Pascal  programowanie
TabReal = array[1..5000] of real; { tablica liczb }
{ rzeczywistych }
PString = ^string
var
TabTabReal : array[1..100] of ^TabReal; { tablica }
ty }
i : integer; { pomocniczy licznik }
procedure IlePamieci;
begin
writeln('Wolne: ', MemAvail, ' max. blok: ', MaxAvail,
' bajtow.');
end;
begin
writeln(s^); { zmienna nie utworzona }
writeln(s^); { utworzona, lecz nie zainicjalizowana }
s^ := 'No wreszcie!'; { inicjalizujemy }
writeln(s^); { teraz jest OK }
dispose(s); { usuwamy }
mark(Sterta); { zaznaczamy 'poziom' sterty }
while MemAvail > SizeOf(TabReal) do { tyle wierszy )
begin
new(TabTabReal[i]); { tworzymy nowy wiersz }
end;
dispose(TabTabReal[3]); { usuwamy jeden wiersz tablicy }
IlePamieci;
IlePamieci;
end.
Pierwsza część programu demonstruje etapy tworzenia, wykorzystania i usunięcia
zmiennej wskazywanej (w naszym przypadku łańcucha) za pomocą procedur new
i dispose. Zauważ, że utworzenie zmiennej wskazywanej nie jest równoznaczne z jej
inicjalizacją, a po wykonaniu procedury dispose treść łańcucha nie jest niszczona,
chociaż może być niekompletna.
Druga część tworzy typową strukturę wielkiej tablicy, przydzielając pamięć dla
poszczególnych wierszy, dopóki to jest możliwe. Zauważ, że po usunięciu trzeciego
wiersza tablicy na ogół okazuje się, że rozmiar największego dostępnego bloku jest
mniejszy od całkowitego rozmiaru wolnego obszaru sterty, co uniemożliwia tworzenie [ Pobierz całość w formacie PDF ]

  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • metta16.htw.pl
  •