var px:^Integer;będzie traktowana jako deklaracja zmiennej wskaźnikowej do obiektu typu całkowitego.
Przydział (alokacja) i zwalnianie (dealokacja) pamięci dynamicznej odbywa się za pomocą dwóch procedur: New(z) oraz Dispose(z). Obie te procedury mają jeden argument: zmienną. Wykonanie procedury New(z) powoduje następujące czynności
1. Określenie wielkości elementu alokowanego typu (wielkość ta musi być znana na etapie kompilacji programu) 2. Znalezienie adresu w pamięci, począwszy od którego jest dostępnych tyle kolejnych komórek, ile potrzeba na zaalokowanie żądanego elementu 3. Zarezerwowanie alokowanego obszaru 4. Przypisanie znalezionego adresu zmiennej z
Jeśli nie ma spójnego fragmentu pamięci, w którym można by zaalokować żądany element, to procedura New(z) powoduje błąd.
Procedura Dispose(z) powoduje tylko jedną rzecz
1. Odblokowanie zarezerwowanego obszaru pamięci i zwrócenie go do puli niewykorzystanych obszarów.
Przyjmijmy, że po wykonaniu Dispose(z) wartość zmiennej z jest nieokreślona. W rzeczywistości często kompilatory po zwolnieniu zaalokowanego obszaru pozostawiają starą wartość adresu na zmiennej, której dealokacja dotyczyła. Bardzo niebezpieczne jest używanie tej wartości do czegokolwiek i nie należy nigdy tego robić.
Zatem zmienne dynamiczne operują w rzeczywistości na adresach. W konsekwencji pamięć rezerwowana na zmienną dynamiczną jest taka sama (zazwyczaj 4 bajty) i niezależna od tego, na co ta zmienna wskazuje.
Zmienne dynamiczne mają ograniczone możliwości wykonywania na nich działań. Możliwe jest porównanie ich wartości, ale tylko pod kątem równości, czyli z operatorów relacyjnych mamy jedynie dwa, a mianowicie = oraz <>. Nie wolno zatem porównywać zmiennych dynamicznych za pomocą operatorów <,<=,>,>=.
Zmiennym dynamicznym można przypisywać wartości, ale jest to ograniczone do innych zmiennych dynamicznych; nie można budować za ich pomocą żadnych wyrażeń. Odwołanie się do wartości elementu wskazywanego przez zmienną dynamiczną odbywa się za pomocą operatora ^. Zatem
z^, to element wskazywany przez zmienną zNależy bardzo uważać, żeby odróżniać przypisanie z:=x od przypisania z^:=x^. W pierwszym przypadku nastąpi przypisanie zmiennej z wartości adresu wskazywanego przez zmienną x. W drugim przypadku nastąpi skopiowanie wartości elementu wskazywanego przez zmienną x elementowi wskazywanemu przez zmienną z. Przyjmijmy w poniższych przykładach, że zmienne x oraz z są zadeklarowane jako var x,z:^Integer. Wykonanie następującej sekwencji instrukcji
New(x); z:=x; z^:=5; Write(x^)
spowoduje wypisanie wartości 5, gdyż obie zmienne wskazują na ten sam obszar pamięci.
Jeśli natomiast wykonalibyśmy następującą sekwencję
New(x); New(z); z^:=5; x^:=z^; z^:=3; Write(x^);
to wypisałaby się wartość 5, gdyż każda z naszych zmiennych wskazuje na inny obszar pamięci i działa na nim autonomicznie. Zastanówmy się, co stałoby się, gdybyśmy tę sekwencję zakończyli przypisaniem z:=x.
Zmienne dynamiczne stwarzają niebezpieczeństwo nieudolnego wykorzystania tego mocnego mechanizmu programistycznego. Wykonanie ostatniego przypisania w powyższym przykładzie spowodowałoby uratę zaalokowanego obszaru pamięci dla zmiennej z. Po prostu zmienna z po przypisaniu z:=x wskazywałaby na ten sam obszar pamięci, co zmienna x i jakiekolwiek odwołanie do x byłoby teraz równoważne odwołaniu do z (włącznie z Dispose). Pamięć przydzielona wcześniej zmiennej z pozostałaby od tej pory niedostępna. Co gorsza, nie udałoby się już nam jej zwolnić, bowiem wykonanie instrukcji Dispose(z) spowodowałoby zwolnienie pamięci przydzielonej zmiennej x! Obszaru przydzielonego zmiennej z nie wskazywałaby już żadna zmienna i nie można byłoby go zwolnić.
Tego typu działanie powoduje powstanie groźnego w skutkach zaśmiecenia pamięci. System operacyjny bowiem będzie rezerwował zajęty obszar do końca działania programu, nie zauważając, że nikt z tego obszaru nie jest już w stanie skorzystać.
Równie groźne są efekty wzajemnego działania na tym samym obszarze. Wyobraźmy sobie następującą sekwencję instrukcji.
New(x); x^:=5; z:=x; ... Dispose(z); ... New(z); z^:=3; Write(x^);
Efekt działania tego kodu jest nieokreślony. Może się zdarzyć, że zostanie wypisana piątka, może trójka (jeśli przez przypadek zmienna z dostałaby ten sam obszar, który wcześniej zwolniła), a może jeszcze coś innego, jeśli po wykonaniu Dispose(z) jakaś inna zmienna dostałaby zwolniony obszar i coś tam w nim zapisała.
Tego typu błędy są trudne do wykrycia, bo w testach w ogóle mogą nie zostać zauważone. Niedeterministyczny charakter alokacji daje tu ogromną gamę możliwych wyników i nie sposób przewidzieć, jak w konkretnym przebiegu programu będą wyglądały wyniki.