Opowieść o programowaniu w Adzie



Pobieranie 0.69 Mb.
Strona13/16
Data28.04.2016
Rozmiar0.69 Mb.
1   ...   8   9   10   11   12   13   14   15   16

Tablice anonimowe (anonimowy typ tablicowy)


Zarówno w przypadku tablic jedno-, jak i wielowymiarowych widzieliśmy przykłady tzw. anonimowego typu tablicowego. Typ taki nie ma własnej nazwy i nie istnieje jako coś odrębnego - zdefiniowany jest niejako na użytek konkretnej zmiennej. Każda zmienna będąca anonimową tablicą należy do innego typu, niemożliwe jest zatem ich porównywanie czy przypisywanie:
Oto dwa fragmenty programów. W pierwszym z nich deklarujemy odrębny typ tablicowy, zaś w drugim używamy typu anonimowego.
type towary is (garnitury, marynarki, spodnie);

type produkcja is array (towary) of natural;

prod_IV, prod_V : produkcja;

...


prod_IV := (garnitury => 3_000, marynarki => 2_000,

spodnie => 5_000);

prod_V := prod_IV; -- możliwe do wykonania

prod_V(garnitury) := prod_IV(spodnie); -- również możliwe - składniki

-- są tego samego typu

if prod_V > prod_IV then ... -- także wykonalne,

-- tablice są jednowymiarowe

-- i tego samego typu

type towary is (garnitury, marynarki, spodnie);

prod_IV, prod_V : array (towary) of natural; -- tablice anonimowe

...

prod_IV := (garnitury => 3_000, marynarki => 2_000,



spodnie => 5_000);

prod_V := prod_IV; -- błąd, tablice nie należą do tego samego typu

prod_V(spodnie):=prod_IV(garniury); -- prawidłowo - elementy tablic są

-- tego samego typu

if prod_V > prod_IV then ... -- błąd - tablic różnych typów nie można

-- porównać


Jak widać, stosowanie tablic anonimowych pozbawione jest sensu, jeżeli w programie używamy kilku tablic o takim samym wyglądzie (a więc mogących należeć do tego samego typu).

Tablice dynamiczne


Tablicą dynamiczną nazywamy tablicę, której rozmiar staje się znany dopiero w momencie wykonywania programu. Można zdefiniować w ten sposób zarówno tablicę anonimową, jak i typ posiadający nazwę. Do tego celu używamy tzw. bloku programu (więcej informacji na ten temat można będzie znaleźć w dalszej części książki):
procedure xxx is

n: integer;

begin

get(n);
declare -- początek bloku



x: array (1..n) of integer;

begin


-- tu używamy tablicy x

end; -- koniec bloku

end xxx;
W trakcie kompilacji programu rozmiar tablicy x nie jest jeszcze znany. Właściwa deklaracje tablicy x, a więc zarezerwowanie dla niej odpowiednio dużego obszaru pamięci, ma miejsce po wczytaniu n (czyli po uruchomieniu programu). Wykonywane są wówczas instrukcje zawarte w części deklaracyjnej bloku - między declare a begin. Tablica x "żyje" tylko wewnątrz bloku, w którym została zadeklarowana, a więc do słowa end (oczywiście jeśli słowo end kończące blok poprzedza bezpośrednio end kończący procedurę, tablica taka funkcjonuje od momentu zadeklarowania do końca programu). Możliwość deklarowania takich tablic jest wielkim udogodnieniem - napisany przez nas program może obsługiwać dowolnie dużo danych, wykorzystując za każdym razem inną, odpowiadającą potrzebom ilość pamięci.
-- dodawanie macierzy kwadratowych

-- o dowolnym rozmiarze


with ada.text_io,ada.float_text_io,ada.integer_text_io;

use ada.text_io,ada.float_text_io,ada.integer_text_io;


procedure pr40 is

n: integer;

begin

put_line("Program wykonuje dodawanie macierzy kwadratowych. ");



put("Podaj rozmiar macierzy> ");

get(n);
declare

type macierz_kwadratowa is array(1..n,1..n) of float;

t1,t2,tw: macierz_kwadratowa;

k: positive_count;

begin


-- wczytywanie tablic

put_line("Podaj wyrazy pierwszej macierzy: ");

for i in t1'range(1) loop

for j in t1'range(2) loop

put('[');put(i,0);put(',');put(j,0);put("]=");

get(t1(i,j));

end loop;

end loop;


put_line("Podaj wyrazy drugiej macierzy: ");

for i in t2'range(1) loop

for j in t2'range(2) loop

put('[');put(i,0);put(',');put(j,0);put("]=");

get(t2(i,j));

end loop;

end loop;

-- obliczanie sumy

for i in tw'range(1) loop

for j in tw'range(2) loop

tw(i,j):=t1(i,j)+t2(i,j);

end loop;

end loop;

-- wypisywanie wyniku

-- w wypadku duzych rozmiarow -- moze byc niezbyt udane

new_line(2);

for i in t1'range(1) loop

k:=1; set_col(k);

for j in t1'range(2) loop

put(t1(i,j),aft=>2,exp=>0);k:=k+10; set_col(k);

end loop;

end loop;

new_line; set_col(k/2);put('+');new_line;

for i in t1'range(1) loop

k:=1; set_col(k);

for j in t2'range(2) loop

put(t2(i,j),aft=>2,exp=>0);k:=k+10; set_col(k);

end loop;

end loop;

new_line;set_col(k/2);put('=');new_line;

for i in t1'range(1) loop

k:=1; set_col(k);

for j in tw'range(2) loop

put(tw(i,j),aft=>2,exp=>0);k:=k+10; set_col(k);

end loop;

end loop;


end; -- koniec bloku

end pr40;



Typy tablicowe bez okeślenia rozmiaru


Istnienie typów tablicowych bez określenia rozmiaru (ang. unconstrained array types) umożliwia tworzenie tablic należących do jednego typu, lecz mających różne rozmiary i zakresy indeksów. Typ taki definiujemy następująco:
type nazwa_typu is array (typ_indeksu range <>) of typ_elementów;
np.
type sznur_cyfr is array (integer range <>) of integer;
Jak widać, w deklaracji tej w miejscu określenia zakresu indeksu znajduje się symbol <> (ang. box), oznaczający brak określenia zakresu indeksu. Zdefiniowany jest natomiast typ indeksu i typ elementów należących do tej tablicy. Rozmiar tablicy (i zakres indeksu dla danej tablicy) określamy dopiero w momencie deklarowania zmiennej należącej do danego typu:
sznur10: sznur_cyfr(1..10);

sznur6: sznur_cyfr(0..5);

sznur2: sznur_cyfr(-3..-2);
Oczywiście podawane granice zakresu indeksu nie mogą przekraczać granic zakresu typu indeksu.
Każdy z zadeklarowanych powyżej "sznurów" jest tablicą o innej długości, innym zakresie i wartości indeksu, należy jednak do tego samego typu - sznur_cyfr. Typ tablicowy bez określenia rozmiaru umożliwia również tworzenie podtypów:
type sznur_liczb_calkowitych is array (integer range <>) of integer;

subtype sznurek is sznur_liczb_calkowitych (1..10);

s1,s2:sznurek;
Indeks każdej z tablic s1, s2 przyjmuje wartości od 1 do 10. Zauważmy, że kolejny typ tablicowy - już o określonym rozmiarze - jest tutaj zdefiniowany jako podtyp typu o rozmiarze nie określonym. w poprzednim przykładzie - gdy deklarowaliśmy tablice pisząc np.
s1: sznur_cyfr(1..10);
deklarowaliśmy w zasadzie anonimowy typ tablicowy będący podtypem typu sznur_cyfr. Porównajmy oba sposoby deklarowania tablic oraz użyteczność typu tablicowego bez określenia rozmiaru:
with ada.text_io;

use ada.text_io;


procedure pr41_1 is
type tab1 is array (integer range 1..10) of integer;

type tab2 is array (integer range 1..5) of integer;

t1:tab1:=(others=>0);

t2:tab2:=(others=>2);


begin
t1(1):=t2(1);

-- t1(1..3):=t2(1..3); -- niewykonalne

-- niewykonalne

-- if t1(1..5)=t2(1..5) then

-- put("poczatkowe kawalki tablic sa rowne");

-- end if;

-- niewykonalne

-- if tab1=tab2 then

-- put("cale tablice tez sa rowne");

-- end if;

-- niewykonalne

-- if t1(1..5)>t2(1..5) then

-- put("poczatkowy kawalek pierwszej tablicy jest wiekszy");

-- end if;

-- niewykonalne

-- if tab1>tab2 then

-- put("pierwsza tablica jest wieksza");

-- end if;


end pr41_1;

with ada.text_io;

use ada.text_io;
procedure pr41_2 is
type typ1 is array (integer range <>) of integer;

subtype tab1 is typ1(1..10);

subtype tab2 is typ1(1..5);

t1:tab1:=(others=>0);

t2:tab2:=(others=>2);
begin
t1(1):=t2(1);

t1(1..3):=t2(1..3);

if t1(1..5)=t2(1..5) then

put("poczatkowe kawalki tablic sa rowne");

end if;

-- niewykonalne



-- if tab1=tab2 then

-- put("cale tablice sa rowne");

-- end if;
if t1(1..5)>t2(1..5) then

put("poczatkowy kawalek pierwszej tablicy jest wiekszy");

end if;

-- niewykonalne



-- if tab1>tab2 then

-- put("cale - pierwsza wieksza");

-- end if;

end pr41_2;


Zmienne i stałe należące do typu tablicowego bez określenia rozmiaru możemy deklarować również ograniczając zakres indeksu niejawnie - poprzez nadanie tablicy wartości początkowej przy użyciu agregatu:
type tab1 is array (positive range <>) of integer;

t1:tab1 := (4,2,0);

type tab2 is array (integer range <>) of integer;

t2:tab2 := (29.30,30);


Indeks tablicy t1 przyjmuje wartości od 1 do 3, zaś tablicy t2 - od integer'first do (integer'first+2). Jak widać, jako początek zakresu indeksu przyjmowana jest najmniejsza wartość w typie danych wyspecyfikowanym jako typ indeksu. Można tego uniknąć stosując w agregacie tablicy notację nazywaną:
t2: tab2 := (1=>29, 2=>30, 3=>30);
Zakres indeksu przyjmuje wówczas żądaną wartość (tutaj - od 1 do 3).
Jak zauważyliśmy poprzednio, każda z tablic należąca do typu tablicowego bez określenia rozmiaru należy właściwie do pewnego jego podtypu określonego przez ograniczenie zakresu indeksu. Przypisując tablicy wartość przy użyciu agregatu możemy mieć do czynienia z niejawną konwersją tegoż agregatu do odpowiedniego podtypu. Zjawisko to nosi nazwę przesuwania (ang. sliding). Ma miejsce tylko w niektórych przypadkach, nie występuje na przykład przy agregatach zawierających słowo kluczowe others:
with ada.text_io,ada.integer_text_io;

use ada.text_io,ada.integer_text_io;


procedure pr42 is

type tab is array (positive range <>) of integer;

t: tab(1..5);
begin
t:=(10..11=>1, 12..14=>4);

-- agregat przesuwa sie tak, ze t(1) i t(2) maja wartosc 1

-- pozostale - wartosc 4

for i in 1..5 loop put(t(i),0);put(' ');end loop; new_line;

t:=(5..6=>9, others=>0);

-- nie ma przesuniecia - t(5) ma wartosc 9

-- pozostale - wartosc 0

for i in 1..5 loop put(t(i),0);put(' ');end loop; new_line;

t:=(3..5=>9, others=>0);

-- nie ma przesuniecia - t(3) do t(5) maja wartosc 9

-- pozostale - wartosc 0

for i in 1..5 loop put(t(i),0);put(' ');end loop; new_line;

t:=(7..9=>0, others=>4);

-- nie ma przesuniecia - wszystkie skladowe tablicy maja -- wartosc 4

for i in 1..5 loop put(t(i),0);put(' ');end loop; new_line;
t:=(8,8,8,others=>0);

-- nie ma przesuniecia - t(1) do t(3) maja wartosc 8,

-- pozostale - wartosc 0

for i in 1..5 loop put(t(i),0);put(' ');end loop; new_line;


end pr42;
Tablice nie mające określenia rozmiaru mogą być zarówno jedno-, jak i wielowymiarowe. w przypadku tablic wielowymiarowych brak określenia zakresu indeksu występować musi we wszystkich wymiarach. Oto przykład prawidłowego użycia typu nie majacego określenia rozmiaru:
type macierz is array (positive range <>,

positive range <>) of float;

m2: macierz(1..2,1..2);

subtype macierz_3_na_3 is macierz(1..3,1..3);

m3_1, m3_2: macierz_3_na_3;
i przykłady nieprawidłowych definicji typów:
type inna_macierz is array (positive range <>,1..3) of float;

type inna_macierz1 is array (1..5,positive range <>) of float;


Warto wiedzieć, że typy string i wide_string są zdefiniowane jako typy tablicowe nie mające określenia rozmiaru:
-- zdefiniowane w pakiecie Standard

type String is array (Positive range <>) of Character;

type Wide_String is array (Positive range <>) of Wide_Character;

1   ...   8   9   10   11   12   13   14   15   16


©absta.pl 2016
wyślij wiadomość

    Strona główna