Wiadomosci wstępne
W Pascalu typy wskaźnikowe zostały wprowadzone w celu umożliwienia posługiwania się w programach tzw. zmiennymi dynamicznymi (odróżnienie od powszechnie znanych i dotychczas stosowanych zmiennych statycznych).
type |
Zmienne statyczne powoływane są przez napisanie w programie odpowiednich deklaracji i definicji, czas ich istnienia związany jest z blokiem, w którym je zadeklarowano (wyjątek - pliki stałe). Powoływane są one z chwilą wejścia do danego bloku, a przestają istnieć w momencie opuszczania bloku.
Zmienne dynamiczne powoływane są na żądanie podczas realizacji programu. Czas ich istnienia nie jest związany z blokową strukturą programu. Zmienne te istnieją dopóki nie zostaną usunięte odpowiednim zleceniem.
Zmienne statyczne powstają na skutek napisania odpowiednich definicji i deklaracji, a zmienne dynamiczne powstają na skutek realizacji instrukcji tworzenia tych zmiennych.
Zasadniczym powodem stosowania zmiennych dynamicznych jest fakt, że umożliwiają one przechowywanie w pamięci operacyjnej obiektów o rozmiarach nie dających się z góry przewidzieć. Przy użyciu rekordu czy też tablicy musimy jawnie określić z ilu i jakich elementów będzie się składać struktura. Pliki umożliwiające tworzenie struktur o różnych rozmiarach ale przechowywane w pamięci zewnętrznej komputera są niewygodne w użyciu. Tworzenie w pamięci dużych struktur danych "na zapas" jest nieuzasadnioną rozrzutnością.
Tworzenie nowych zmiennych dynamicznych umożliwia standardowa procedura New, a ich usuwanie procedura Dispose. Zmienne dynamiczne, ze względu na sposób ich tworzenia nie mają nazwy (identyfikatora), stąd nazywa się je czasami zmiennymi niejawnymi (anonimowymi). Odwołanie do zmiennych dynamicznych typu Typ umożliwiają zmienne pomocnicze typu wskaźnikowego (zmienne wskaźnikowe), zwane wskaźnikami. Wskazywany przez nie odpowiedni obiekt (zmienna dynamiczna) nazywany jest zmienną wskazywaną.
Tworzenie struktury dynamicznej dowolnej wielkości umożliwia fakt, że zmienna wskazywana nie musi być zmienną statyczną (np. zmienna wskazywana może być rekordem zawierającym pole typu wskaźnikowego).
Dynamiczne struktury danych to proste i złożone struktury danych, którym pamięć może być przydzielana i zwalniana podczas wykonywania programu. Dynamiczne struktury listowe to uporządkowane zbiory składników, niekoniecznie o jednakowych typach. Wśród tych struktur można wyróżnić:
stosy (stack) - wstawianie, usuwanie i dostęp są możliwe tylko w jednym końcu, wierzchołku stosu (struktura LIFO - Last Input First Output)
kolejki (queue) dołączanie wskaźników możliwe jest tylko w jednym końcu, a usuwanie w drugim (struktura FIFO - First Input First Output)
listy liniowe (jednokierunkowe, dwukierunkowe, cykliczne) - dla każdego składnika takiej listy określony jest składnik poprzedni i następny; w dowolnym miejscu takiej struktury można usunąć lub dołączyć element
drzewa - struktury, w których dla każdego składnika (poza pierwszym) określony jest jeden składnik poprzedni, a dla każdego składnika poza ostatnim określonych jest n (n>=2) składników następnych
grafy - definiowane przez dwa zbiory: zbiór wierzchołków i krawędzi definiujący powiązania pomiędzy poszczególnymi elementami
Sposób działania stosu (wg. A.Marciniaka, Turbo Pascal 5.5)
Stos to struktura liniowo uporządkowanych elementów (składników) stosu, z których tylko największy (ostatnio umieszczony) jest dostępny. Miejsce dostępu to wierzchołek stosu (jedyne miejsce, do którego można dołączać lub z
którego można usuwać elementy - składniki).
Każdy element (składnik) stosu jest rekordem, w którym:
pierwsze pole to umieszczane na stosie Dane (umowna nazwa pewnej uprzednio zdefiniowanej struktury typu TypDanych)
drugie to wskaźnik pokazujący składnik - element (a dokładniej jego adres) następujący po nim (położony na stosie poprzednio); wskaźnik ostatniego składnika stosu wskazuje na adres pusty (nil)
W celu tak zwanego ustalenia uwagi i ułatwienia tworzenia stosu a następnie jego przetwarzania zdefiniujemy następujące typy.
type |
TypDanych oznacza pewien typ standardowy lub zdefiniowany przez programistę. Zakładamy, że wszystkie dane są tego samego typu (mają tą samą wielkość). W ogólności TypDanych może być różny dla różnych składników.
Typ wskaźnikowy WskaźnikStosu związany jest ze zbiorem wskazań danych typu SkladnikStosu. Zmienne typu WskaznikStosu ( w naszym przykładzie Wierzcholek) określają adresy pamięci danych typu SkladnikStosu.
Pewnym kompromisem w tworzeniu złożonych dynamicznych struktur danych jest utworzenie statycznej struktury, najczęściej tablicy, w której zapamiętywane są wskaźniki do obiektów (składników) tworzonych w pełni dynamicznie.
type
procedure InitScreen (var Screen : ScreenTypePtr);
procedure NaStos (var Wierzcholek: WskaznikStosu;
procedure ZeStosu (var Wierzcholek: WskaznikStosu; |
Porównanie programu o strukturze statycznej i dynamicznej
type |
type { U W A G A : te definicje typow moga byc zamienione miejscami } |
Ul, U2 to wskaźniki (pointery) do odpowiednich wskazywanych przez nie struktur danych (pewne adresy, mówiące gdzie fizycznie w pamięci są one zapamiętane)
U1^, U2^ wskazują (pokazują) na odpowiednie struktury danych umieszczone w pamięci zarezerwowanej na dynamiczne struktury danych
Uczniowie =^Uczen definicja typu wskazującego na typ Uczen
Uwaga: Deklaracja zmiennych Ul i U2 może być również w inny sposób, bez powoływania typu wskaźnikowego Uczniowie : Ul, U2 :^Uczen