Tablice dynamiczne w Pascalu
Tablice dynamiczne w języku Pascal.
Czytelnicy zaznajomieni z Borland Delphi z pewnością wiedzą, że rozszerzona składnia języka Object Pascal pozwala na definiowanie tablic otwartych, o zmieniającej się liczbie elementów w trakcie wykonywania programu, innymi słowy dynamicznych. Niestety język Pascal został rozwinięty dla systemu Windows (i nadal jest rozwijany przez Borland'a), a co z tymi, którzy piszą programy dla trybu znakowego. Użytkownicy Delphi nie mogą narzekać, środowisko to pozwala tworzyć programy konsolowe, a co z programistami Pascala w systemach Linux (Unixowych). Tam niestety rzuca się w oczy trochę dyskomfort w pracy z narzędziami GNU Pascal, konfigurując jednak odpowiednio środowisko pracy (np. edytor Emacs) można osiągnąć nie mniejszą wygodę. Również i tam sytuację ratuje firma Borland ze swoim znakomitym Kylix'em, w ten sposób rozwijając język Pascal i dla systemów Unixowych. Ale co z tablicami dynamicznymi? Możemy się tutaj (nie korzystając z języka Object Pascal) posłużyć sposobem znanym z języka C. Wykorzystamy, oczywiście wskaźniki. Po pierwsze zadeklarujmy sobie nowy typ danych i nazwijmy go macierz:
type matrix=^byte;
Jak widzimy jest to typ wskaźnikowy, stwórzmy zmienną tego typu :
var m: matrix;
i w ciele programu przydzielmy jej w pamięci np. 10 bajtów:
getmem (m, 10);
teraz powróćmy do klauzuli deklaracji zmiennych i dodajmy dwie zmienne, które zapamiętają położenie w pamięci początku naszej tablicy:
var s, o: word;
Jedna zmienna zapamięta segment, a druga przesunięcie względem segmentu:
s:=seg(m);
o:=ofs(m);
Teraz możemy już zwolnić nasz wskaźnik, powodując, że pamięć nie będzie już dla niego rezerwowana:
freemem (m, 10);
Pamięć uprzednio zajmowana jest zwolniona, my mamy namiary do niej, wieć nic nie stoi na przeszkodzie aby wykorzystać tablicę (przy wykorzystaniu tablicy predefiniowanej mem):
mem[s:o]:=25;
mem[s:o+1]:=50;
Tym sposobem możemy pamiętać sobie zmienne w pamięci, nie zajmując miejsca w stosie zmiennych. Oczywiście odczyt przebiega w sposób analogiczny, np.:
writeln (mem[s:o]);
writeln (mem[s:o+1]);
Na ekranie powinniśmy zobaczyć nasze dwie liczby. Rozwiązanie takie ma ogromną wadę. Jeżeli chcielibyśmy coś jeszcze umieścić w pamięci należy dbać o to aby nie dochodziło do kolizji, inaczej będziemy zamazywać sobie dane. Jeżeli zechcemy umieścić jeszcze jedną zmienną dynamiczną, to po zwolnieniu poprzedniej jest ogromne prawdopodobieństwo, że zamażemy sobie tablice. Ale w sytuacji, gdy nie korzystamy ze zmiennych dynamicznych, pisząc proste programy można wykorzystać dostępną pamięć w ten sposób.
Czytelnicy zaznajomieni z Borland Delphi z pewnością wiedzą, że rozszerzona składnia języka Object Pascal pozwala na definiowanie tablic otwartych, o zmieniającej się liczbie elementów w trakcie wykonywania programu, innymi słowy dynamicznych. Niestety język Pascal został rozwinięty dla systemu Windows (i nadal jest rozwijany przez Borland'a), a co z tymi, którzy piszą programy dla trybu znakowego. Użytkownicy Delphi nie mogą narzekać, środowisko to pozwala tworzyć programy konsolowe, a co z programistami Pascala w systemach Linux (Unixowych). Tam niestety rzuca się w oczy trochę dyskomfort w pracy z narzędziami GNU Pascal, konfigurując jednak odpowiednio środowisko pracy (np. edytor Emacs) można osiągnąć nie mniejszą wygodę. Również i tam sytuację ratuje firma Borland ze swoim znakomitym Kylix'em, w ten sposób rozwijając język Pascal i dla systemów Unixowych. Ale co z tablicami dynamicznymi? Możemy się tutaj (nie korzystając z języka Object Pascal) posłużyć sposobem znanym z języka C. Wykorzystamy, oczywiście wskaźniki. Po pierwsze zadeklarujmy sobie nowy typ danych i nazwijmy go macierz:
type matrix=^byte;
Jak widzimy jest to typ wskaźnikowy, stwórzmy zmienną tego typu :
var m: matrix;
i w ciele programu przydzielmy jej w pamięci np. 10 bajtów:
getmem (m, 10);
teraz powróćmy do klauzuli deklaracji zmiennych i dodajmy dwie zmienne, które zapamiętają położenie w pamięci początku naszej tablicy:
var s, o: word;
Jedna zmienna zapamięta segment, a druga przesunięcie względem segmentu:
s:=seg(m);
o:=ofs(m);
Teraz możemy już zwolnić nasz wskaźnik, powodując, że pamięć nie będzie już dla niego rezerwowana:
freemem (m, 10);
Pamięć uprzednio zajmowana jest zwolniona, my mamy namiary do niej, wieć nic nie stoi na przeszkodzie aby wykorzystać tablicę (przy wykorzystaniu tablicy predefiniowanej mem):
mem[s:o]:=25;
mem[s:o+1]:=50;
Tym sposobem możemy pamiętać sobie zmienne w pamięci, nie zajmując miejsca w stosie zmiennych. Oczywiście odczyt przebiega w sposób analogiczny, np.:
writeln (mem[s:o]);
writeln (mem[s:o+1]);
Na ekranie powinniśmy zobaczyć nasze dwie liczby. Rozwiązanie takie ma ogromną wadę. Jeżeli chcielibyśmy coś jeszcze umieścić w pamięci należy dbać o to aby nie dochodziło do kolizji, inaczej będziemy zamazywać sobie dane. Jeżeli zechcemy umieścić jeszcze jedną zmienną dynamiczną, to po zwolnieniu poprzedniej jest ogromne prawdopodobieństwo, że zamażemy sobie tablice. Ale w sytuacji, gdy nie korzystamy ze zmiennych dynamicznych, pisząc proste programy można wykorzystać dostępną pamięć w ten sposób.



Poza tym FPC ma tablice dynamiczne, których długość można zmieniać za pomocą SetLength(Tab), więc nie trzeba nawet samemu dbać o alokację i zwalnianie pamięci. A dla tych co lubią (dla mnie):
Var
Tab : Pointer;
Begin
GetMem(Tab, 1024);
Byte((Tab+10)^):=100;
DWord((Tab+11)^):=$10000000;
WriteLn(Byte((Tab+10)^)); // 100
WriteLn(DWord((Tab+11)^)); // 268435456
FreeMem(Tab, 1024);
End.
Innym sposobem są listy jedno- dwu- kierunkowe (są też i inne, ale nie wnikałem w ich szczegóły aż tak bardzo jak w te
Wiadome... wszystko ma swoje zastosowanie, tylko trzeba wiedzieć gdzie i kiedy je wykożystać.
A co do dynamiczności w artykule, to nie wiem, czy bym skusił się na przydzielanie 10 bajtów dla zmiennej typu ^Byte. Bardziej eleganckim sposobem jest:
Type
PByteArray = ^TByteArray;
TByteArray = Array[0..65535] of byte;
Var
tab:PByteArray;
Begin
GetMem(tab,1000);
...
FreeMem(Tab,1000);
End.
Wszystko sprawa gustu i upodobań
Pozdrawiam.
Jest nowszy
\"Error: identifier not found \'mem\' \",
a następny błąd:
\"Fatal: Syntax error, \']\' expected, but \':\' found\"
Wydaje mi się, że chyba łatwiej już wykorzystać listy i inne twory dynamiczne.