TYPY STRUKTURALNE W PASCALU
Typy strukturalne w Pascalu reprezentują 4 rodzaje struktur: tablice, rekordy, zbiory i pliki. Ograniczeniem rozmiaru jest ok. 64 kB pamięci (65520 B).
Typ tablicowy składa się z ustalonej liczby elementów tego samego typu składowego (prosty lub łańcuchowy) albo strukturalny. Za pomocą tablic przedstawia się regularne struktury danych np. wektory czy macierze. Dostęp do elementów uzyskuje się za pomocą indeksowania, wyrażeniem zgodnym i będącym w zakresie zdefiniowanego typu tablicowego. Np.:
Type wektor =Array [0..100] Of Integer;
macierz2=Array [1..20] Of Array [1..50] Of Real;
macierz3=Array [1..10,1..20,1..30] Of Real;
tablica =Array [Boolean, 1..20,znak] Of Char; {=Array [Boolean] Of Array[1..20] Of Array [znak] Of Char;}
Typ rekordowy - rekordem w Pascalu nazywamy złożoną strukturę danych, której składowe, nazywane polami, mogą być różnych typów. Poszczególne pola mogą same być strukturami złożonymi. Definicja typu rekordowego określa dla każdego pola jego typ i identyfikator. Rozpoczyna się słowem kluczowym record, po którym następują deklaracje pól, kończy się słowem kluczowym end; Kolejne deklaracje oddziela się średnikami. Ostatnia z nich może być wariantowa (składa się z kluczowego słowa case wyróżnik of wykaz-wariantów). Przykłady zmiennych rekordowych:
Type data=Record
rok : Integer;
miesiac : 1..12; {9typy okrojone}
dzien : 1..31
end;{data}
posiadanie={posiada,nie_posiada};{typ porządkowy}
dana=Record
nazwisko:String [20];
imie :String [15];
data_ur :data;
adres :String[30];
Case dzieci:posiadanie Of
posiada :(data_ur_dziecka:Array[1..10] Of data;
nie_posiada:(znak:Char)
End;{dana}
Typ zbiorowy jest zbiorem potęgowym danego typu rzeczywistego, tzn. jest zbiorem wszystkich podzbiorów tego typu w tym także typu pustego. Definicja ma postać: type identyfikator-typu = Set Of typ-porządkowy; Liczba elementów typu porządkowego, będącego typem bazowym w takiej definicji nie może przekraczać 256, przy czym ich liczby porządkowe muszą należeć do przedziału 0..255. Wartości typu zbiorowego podaje się przez wypisanie listy elementów danego zbioru oddzielonych przecinkami w nawiasach kwadratowych. Zapis [] oznacza zbiór pusty. Np.:
type
dzien_pracy=Set Of [poniedzialek, wtorek, sroda, czwartek, piatek];
znaki =Set Of Char;
male_litery=Set Of 'a'..'z';
miesiac =[sty, lut, mar, kwi, maj, cze, lip, sie, wrz,
paz, lis, gru];
z_mies =Set Of miesiac;
Var nazwa_mies : miesiac;
z_nazw : z_mies;
Typ plikowy jest ciągiem elementów tego samego typu, liczba jego składowych jest zmienna. Reprezentuje fizyczny zbiór danych o dostępie sekwencyjnym. Oznacza to, że aktualnie mamy dostęp do 1 elementu, a do innych można dotrzeć po wykonaniu odpowiednich operacji. Zależy od przebiegu programu, skojarzenia pliku z fizycznym zbiorem danych (na dysku, wyprowadzanych na drukarkę itp). Definicja:
type id_pliku = File Of typ-elementow; id_pliku = File;
typ-elementów oznacza identyfikator dowolnego typu prostego, opis typu porządkowego, strukturalnego lub wskaźnikowego. Istnieje predefiniowany plik tekstowy o nazwie Text, którego elementami są wiersze podzielone na znaki. Na końcu wiersza wstawiona jest para znaków CR/LF (carriage return, line feed = powrót karetki, zmiana linii), koniec pliku znaczy znak ^Z. Pliki tekstowe służą do obsługi dostępnych zbiorów fizycznych przy pomocy klawiatury, monitora, drukarki. Np.:
type dane =File Of Integer;
wyniki =File Of Real;
complex=Record
re, im : Real
End;
var daty : File Of data;
zesp : File Of complex;
Z punktu widzenia każdego użytkownika tablica jest po prostu ciągiem jednolitych "szufladek" przechowujących dane tego samego typu. Każda szufladka jest identyfikowana numerem - tzw. indeksem - który musi być typu porządkowego (trudno bowiem wyobrazić sobie element tablicy o numerze półtora). Tablice deklarowane są za pomocą słowa kluczowego array (tablica), zaś składnia deklaracji jest następująca:
nazwa_tablicy : array[indeks_dolny..indeks_górny] of typ;
W nawiasach kwadratowych musimy umieścić dwie stałe określające najmniejszy i największy dopuszczalny indeks tablicy. Pamiętajmy, że wartości użyte w deklaracji muszą być znane w momencie kompilacji programu (najczęściej podawane są jawnie, ewentualnie w postaci prostych wyrażeń dopuszczalnych w definicjach stałych). Pascal wymaga określenia rozmiaru tablicy w chwili kompilacji i nie dopuszcza użycia tzw. tablic dynamicznych (o rozmiarze określanym podczas wykonania) Obydwa indeksy mogą mieć dowolne wartości, ale muszą być tego samego typu porządkowego, a górny indeks nie może być mniejszy od dolnego. Zwykle tablice indeksuje się od 1, jak np. tablicę autorów książek:
var
Autorzy : array[1..1000] of string[30];
ale całkowicie normalne są również deklaracje:
Sinusy : array[0..359] of real;
Odchylka : array[-10..10] of real;
Tablice wcale nie muszą być indeksowane liczbami. Jeśli np. chcemy zliczyć częstość występowania w tekście poszczególnych znaków alfabetu, możemy użyć efektownej konstrukcji
Liczniki : array['a'..'z'] of word;
Każdy z elementów takiej tablicy jest licznikiem o pojemności około 65 tysięcy "impulsów", adresowanym za pomocą odpowiedniego znaku alfabetu.
Aby odwołać się do elementu tablicy o danym numerze, musimy użyć składni
nazwa_tablicy[indeks]
gdzie indeks jest numerem żądanego elementu (stałą lub zmienną typu porządkowego o wartości zawartej pomiędzy dolnym a górnym zadeklarowanym indeksem). Aby zatem wyświetlić trzecią z kolei pozycję tablicy autorów, wystarczy użyć instrukcji
writeln(Autorzy[3]);
zaś instrukcja
Autorzy[5] := 'Ernest Hemingway';
ustali nazwisko autora piątej książki w katalogu. W przypadku tablicy liczników znaków odwołania będą wyglądały następująco:
{ zwiększy licznik dla znaku o 1 }
writeln(Liczniki['a'];
{ wyświetli wartość}
{ licznika znaków 'a' }
Próba użycia indeksu leżącego poza zadeklarowanym zakresem kończy się na ogół błędem wykonania, o ile opcja kontroli zakresów (Options-Compiler-Range checking) nie została wyłączona (uwaga: domyślnie opcja ta jest wyłączona!). W tym ostatnim przypadku odczyt z tablicy zwróci bezsensowną wartość, zaś zapis może mieć złe skutki (z zawieszeniem komputera włącznie), gdyż wartość zostanie wstawiona w miejsce przeznaczone na coś zupełnie innego.
Dwa główne obszary zastosowania tablic to bazy danych (czyli programy służące do przechowywania i zarządzania informacją opisującą rzeczywiste obiekty, np. książki w bibliotece, towary w hurtowni itp.) oraz oprogramowanie inżynierskie i naukowe, wykorzystujące tzw. wektory i macierze, czyli liniowe i prostokątne tablice liczb. Jak zapisać wektor (czyli liniową lub jednowymiarową tablicę liczb), już wiemy. Przykładowemu wektorowi złożonemu z dziesięciu liczb rzeczywistych
będzie odpowiadała tablica
Wektor : array[1..10] of real
zaś dla prostokątnej tablicy (macierzy) o wymiarach m na n:
użyjemy deklaracji
Macierz : array[1..M, 1..N] of real
Jak widać, tworzenie tablic odpowiadających dwu- i więcejwymiarowym strukturom danych nie stanowi w Pascalu trudnego zadania. Ogólna składnia deklaracji tablicy wielowymiarowej wygląda tak:
nazwa_tablicy : array[zakres_1, zakres_2, ... zakres_n] of typ
gdzie zakres_k opisuje zakres indeksów dla k-tego wymiaru i ma formę początek..koniec. Dla tablic dwuwymiarowych pierwszy indeks oznacza numer wiersza, zaś drugi - numer kolumny (w pamięci komputera dane przechowywane są wierszami ułożonymi jeden za drugim). Chociaż Pascal nie narzuca ograniczenia na liczbę wymiarów tablicy (jedynymi ograniczeniami są łączny rozmiar elementów, nie mogący przekraczać 65520 bajtów, oraz zakres indeksów, nie mogący wykraczać poza zakres liczb całkowitych), tablic więcej niż dwuwymiarowych używa się bardzo rzadko. Tablice dwuwymiarowe stosowane są przede wszystkim w programach obliczeniowych (realizujących obliczenia tzw. rachunku macierzowego). Aby jednak nie poprzestawać na samym opisie, zademonstruję krótki przykład: oto program pozwalający na wprowadzenie z klawiatury wartości elementów macierzy o wymiarach 3 na 3 i wyświetlający największy wprowadzony element oraz sumę wszystkich elementów leżących na przekątnej i powyżej niej.
program Macierz3x3;
{ program demonstruje elementarne obliczenia macierzowe }
t : array[1..3, 1..3] of real;
{ macierz 3x3 }
max, sum : real;
{ tymczasowe maksimum i suma elementów }
i, j : integer;
{ liczniki wierszy i kolumn }
begin
{ wczytanie zawartości macierzy }
for i := 1 to 3 do
for j := 1 to 3 do
write('Podaj element macierzy x[',i,',',j,']: ');
akunseth