PP1 wyklad 9


Podstawy Programowania
Wykład dziewiąty:
Tablice wielowymiarowe i rekordy
1.Tablica wielowymiarowa  typ
Poznane dotąd przez nas tablice były tablicami jednowymiarowymi. Do
określenia w takich tablicach położenia elementu wystarczy podać tylko
wartość jego jedynego indeksu. Inaczej, w takich tablicach element ma tylko
jedną współrzędną, którą stanowi jego indeks. Język Pascal, podobnie jak inne
współczesne języki programowania pozwala na używanie tablic wielowy-
miarowych, w których każdy element posiada kilka indeksów (współrzędnych).
Najczęściej spotykane w praktyce są tablice dwu i trójwymiarowe, choć można
stosować tablice o większej liczbie wymiarów. Na tym wykładzie omówione będą
głównie tablice dwuwymiarowe. Jednowymiarowe tablice są czasem używane
do reprezentowania wektorów, natomiast najczęstszym zastosowaniem tablic
dwuwymiarowych jest reprezentowanie macierzy. Typ tablicy dwuwymiarowej
możemy określić w Pascalu, w sekcji type programu lub podprogramu, na trzy
różne, podstawowe sposoby. Pierwszy sposób definicji typu tablicy
dwuwymiarowej możemy opisać następującym wzorcem:
wiersz = array [id .. ig] of typ_elementu;
macierz = array [id1 .. ig1] of wiersz;
W tym wypadku definicja typu tablicy jest dwustopniowa. Najpierw określamy
typ elementów które znajdują się w pojedynczym wierszu, a następnie
definiujemy ile wierszy znajdzie się w jednej macierzy. Liczba elementów
w wierszu określa liczbę kolumn macierzy. Zakresy wartości indeksów
określamy tak samo, jak to ma miejsce w przypadku tablic jednowymiarowych.
Jeśli id=id1 i ig=ig1 lub gdy oba typy mają tyle samo elementów, to mamy do
czynienia z macierzą kwadratową. Sposób definiowania typów tablic
dwuwymiarowych łatwo rozszerzyć na tablice o większej liczbie wymiarów. Jeśli
chcielibyśmy zdefiniować typ tablicy trójwymiarowej, to następny typ tablicowy
miałby elementy typu macierz. Inny sposób deklaracji typu tablicy
dwuwymiarowej wynika z zaprezentowanego wyżej. Oto wzorzec definicji:
macierz = array [id .. ig] of array [id1 .. ig1] of typ_elementu;
Jak wspomniano wcześniej jest też trzeci sposób definicji typu macierzowego:
macierz = array [id .. ig, id1 .. ig1] of typ_elementu;
Jeśli w programie zdecydujemy się używać funkcji low i high do określania in-
deksów dolnych i górnych zarówno dla wierszy, jak i dla kolumn, to będziemy
zmuszeni zastosować pierwszy sposób definiowania typu tablicy dwuwy-
2
miarowej. Jeśli jednak nie będziemy używać tych funkcji, to możemy używać
dowolnego sposobu określania typów tablic dwuwymiarowych.
2.Zmienne
Możliwe jest zadeklarowanie zmiennej, która jest tablicą dwuwymiarową
z użyciem typu nienazwanego (anonimowego). Zmienną taką deklarujemy
używając składni podobnej do składni definicji typu podanej w drugim lub
trzecim wzorcu. Można również zadeklarować macierz o typie anonimowy,
której wiesze będą typu nazwanego. Zadeklarowanie zmiennej typu który
zdefiniowaliśmy wcześniej przebiega tak samo, jak w przypadkach zmiennych
innych typów. Możliwe jest również zadeklarowanie zmiennych
zainicjalizowanych, w sekcji const programu lub podprogramu. W tym wypadku
trzeba oczywiście określić wartość początkową elementów takiej tablicy. Jeśli
będzie to macierz elementów typu byte o dwóch wierszach i dwóch kolumnach,
to można ją zadeklarować następująco:
m:macierz = ((1,2),(3,4));
Wartości w nawiasach wewnętrznych to oczywiście wartości elementów
odpowiednio pierwszego i drugiego wiersza macierzy.
3.Określenie położenia elementu w tablicy dwuwymiarowej
Załóżmy, że mamy daną macierz o nazwie mac. Jeśli chcemy zapisać lub
odczytać wartość pojedynczego elementu tej macierzy, to musimy podać
kolumnę i wiersz, w których ten element jest położony. Możemy zrobić to na
dwa sposoby:
mac[iw,ik]
lub
mac[iw][ik]
gdzie ik i iw oznaczają odpowiednio numer kolumny i numer wiersza
w macierzy. Drugi sposób jest używany również w innych językach
programowania, takich jak C, C++, Java, natomiast pierwszy jest właściwy dla
Pascala.
4.Przekazywanie tablic wielowymiarowych przez parametry
3
Nie istnieje prosty sposób na przekazanie macierzy typu anonimowego przez
parametr. W przypadku typów nazwanych deklarujemy po prostu parametr
formalny o takim samym typie, jak macierz, którą chcemy przekazać. Podobnie,
jak w przypadku tablic jednowymiarowych tablice wielowymiarowe powinniśmy
przekazywać wyłącznie przez stałą lub zmienną.
5.Operacje na macierzach
Na tablicach dwuwymiarowych, które są macierzami możemy wykonywać
wszystkie operacje przewidziane przez rachunek macierzowy: dodawanie,
odejmowanie, mnożenie, transponowanie, odwracanie, obliczanie wyznacznika.
Na tym wykładzie zostanie przedstawiony program realizujący pierwsze cztery
z tych operacji:
program macierze;
uses
crt;
type
wiersz = array [1..3] of byte;
macierz = array [1..2] of wiersz;
wiersz2 = array [1..2] of byte;
macierz2 = array [1..3] of wiersz2;
wiersz3 = array [1..2] of word;
macierz3 = array [1..2] of wiersz3;
var
mac:macierz;
mac2:macierz;
mac3:macierz;
mac4:macierz2;
mac5:macierz3;
procedure wypelnij(var m:macierz);
var
i,j:byte;
begin
for j:=low(macierz) to high(macierz) do
for i:=low(wiersz) to high(wiersz) do
4
m[j,i]:=random(10);
end;
procedure wypelnij2(var m:macierz2);
var
i,j:byte;
begin
for j:=low(macierz2) to high(macierz2) do
for i:=low(wiersz2) to high(wiersz2) do
m[j,i]:=random(10);
end;
procedure wypisz(const m:macierz);
var
i,j:byte;
begin
for j:=low(macierz) to high(macierz) do
begin
for i:=low(wiersz) to high(wiersz) do
write(m[j][i]:3);
writeln;
end;
writeln;
end;
procedure wypisz2(const m:macierz2);
var
i,j:byte;
begin
for j:=low(macierz2) to high(macierz2) do
begin
for i:=low(wiersz2) to high(wiersz2) do
write(m[j][i]:3);
writeln;
end;
5
writeln;
end;
procedure wypisz3(const m:macierz3);
var
i,j:byte;
begin
for j:=low(macierz3) to high(macierz3) do
begin
for i:=low(wiersz3) to high(wiersz3) do
write(m[j][i]:6);
writeln;
end;
writeln;
end;
procedure suma(const m1,m2:macierz; var m3: macierz);
var
i,j:byte;
begin
for j:=low(macierz) to high(macierz) do
for i:=low(wiersz) to high(wiersz) do m3[j,i]:=m1[j,i]+m2[j,i];
end;
procedure roznica(const m1,m2:macierz; var m3:macierz);
var
i,j:byte;
begin
for j:=low(macierz) to high(macierz) do
for i:=low(wiersz) to high(wiersz) do
m3[j,i]:=m1[j,i]-m2[j,i];
end;
procedure iloczyn(const m1:macierz; const m2:macierz2; var m3:macierz3 );
var
i,j,k:byte;
6
begin
for i:=low(macierz) to high(macierz) do
for j:=low(wiersz2) to high(wiersz2) do
for k:=low(wiersz) to high(wiersz) do
m3[i,j]:=m3[i,j]+m1[i,k]*m2[k,j];
end;
procedure transponowanie(const m1:macierz; var m2:macierz2);
var
i,j:byte;
begin
for i:=low(macierz) to high(macierz) do
for j:=low(wiersz) to high(wiersz) do
m2[j,i]:=m1[i,j];
end;
begin
clrscr;
randomize;
wypelnij(mac);
wypelnij(mac2);
writeln('Macierz pierwsza: ');
wypisz(mac);
writeln('Macierz druga: ');
wypisz(mac2);
suma(mac,mac2,mac3);
writeln('Suma: ');
wypisz(mac3);
roznica(mac3,mac,mac2);
writeln('Roznica mac3-mac1 : ');
wypisz(mac2);
readln;
clrscr;
writeln('Macierz pierwsza: ');
7
wypisz(mac);
transponowanie(mac,mac4);
writeln('Transponowana macierz pierwsza: ');
wypisz2(mac4);
readln;
clrscr;
writeln('Macierz pierwsza:');
wypisz(mac);
wypelnij2(mac4);
writeln('Macierz druga: ');
wypisz2(mac4);
iloczyn(mac,mac4,mac5);
writeln('Iloczyn macierzy: ');
wypisz3(mac5);
readln;
end.
Procedury wypelnij i wypelnij2 służą do wypełniania liczbami pseudolosowymi
macierzy typu macierz i macierz2, natomiast procedury wypisz, wypisz2
i wypisz3 służą do wypisywania kolejno macierzy typu macierz, macierz2
i macierz3. Możemy dodać dwie macierze, jeśli są takich samych wymiarów,
tzn. jeśli mają jednakową liczbę kolumn i jednakową liczbę wierszy. W wyniku
otrzymamy trzecią macierz, o takich samych wymiarach jak dwie pierwsze.
Dodawanie macierzy jest zrealizowane w procedurze suma. Przez parametry m1
i m2 przekazujemy do procedury macierze które chcemy dodać, a przez
parametr m3 zwracana jest macierz wynikowa1. Operacja dodawania macierzy
polega na policzeniu sumy odpowiadających sobie elementów obu macierzy,
które są argumentami dodawania. Wywołanie funkcji low(macierz) określa
numer pierwszego wiersza macierzy, wywołanie high(macierz) określa numer
ostatniego wiersza macierzy. Odejmowanie macierzy można przeprowadzić pod
takimi samymi warunkami jak dodawanie. Operacja ta jest zrealizowana
w procedurze roznica. Operacja transponowania macierzy polega na zamianie
jej wierszy na kolumny i kolumn na wiersze. Potrzebujemy więc nowego typu
macierzowego, który określałby macierze o takiej liczbie wierszy, jak liczba
kolumn transponowanej macierzy i o takiej liczbie kolumn, jak liczba wierszy
1 Tablic wielowymiarowych, podobnie jak tablic jednowymiarowych nie da się zwrócić jako wynik
działania funkcji. Podobna sytuacja występuje w przypadku innych typów strukturalnych.
8
tej macierzy2. Takim typem jest typ macierz2. Transponowanie macierzy
zrealizowane jest w procedurze transponowanie. Przez pierwszy parametr
przekazujemy macierz, którą chcemy poddać tej operacji, przez drugi parametr
zwracamy macierz wynikową. Cała operacja polega na odpowiednim
przepisaniu elementów z jednej macierzy do drugiej (indeks kolumny pierwszej
macierzy powinien odpowiadać indeksowi wiersza drugiej macierzy, a indeks
wiersza pierwszej macierzy powinien odpowiadać indeksowi kolumny drugiej
macierzy, itd.). Dwie macierze możemy pomnożyć przez siebie, jeśli liczba
kolumn pierwszej macierzy jest równa liczbie wierszy drugiej macierzy
(mnożenie macierzy jest nieprzemienne). Wartość pojedynczego elementu
macierzy wynikowej otrzymujemy mnożąc wartości elementów odpowiedniego
wiersza macierzy pierwszej przez wartości elementów odpowiedniej kolumny
drugiej macierzy i sumując otrzymane wyniki. Przykładowo wartość elementu
macierzy wynikowej, który leży w pierwszej kolumnie i pierwszym wierszu
otrzymujemy mnożąc wartości kolejnych elementów pierwszego wiersza
pierwszej macierzy przez wartości kolejnych elementów pierwszej kolumny
drugiej macierzy i dodając do siebie poszczególne wyniki (krócej: mnożąc
pierwszy wiersz pierwszej macierzy przez pierwszą kolumnę drugiej macierzy).
Operacja mnożenia macierzy jest zaimplementowana w postaci procedury
iloczyn. Zmienna i określa wiersz pierwszej macierzy, zmienna j określa
kolumnę drugiej macierzy, natomiast zmienna k służy do  poruszania się po
poszczególnych elementach tego wiersza i tej kolumny.
6.Typ rekordowy
Rekordy są strukturami danych, które mogą służyć do przechowywania
wartości różnych typów. Typ rekordowy definiuje się w sekcji type programu
lub podprogramu według następującego wzorca:
nazwa_typu_rekordowego = record
nazwa_pola_1: typ_pola_1;
nazwa_pola_2: typ_pola_2;
.
.
.
nazwa_pola_n: typ_pola_n;
end;
Poszczególne składowe rekordu nazywamy polami. Typ rekordowy w Turbo
Pascalu nie może określać zmiennej, której rozmiar jest większy niż 64 KB.
2 Nie jest to konieczne, jeśli macierz jest kwadratowa.
9
Typy pól rekordu mogą być dowolne. Jeśli któreś z pól rekordu jest rekordem,
to mówimy, że mamy do czynienia z rekordem zagnieżdżonym. Jednym
z najczęstszych przypadków użycia rekordu jest przechowywanie informacji
o osobie. Typ rekordu, który przechowuje takie informacje może być
zdefiniowany następująco:
type
osoba = record
imie:string[30];
nazwisko: string[50];
wiek:byte;
end;
Czasem rekord składa się wyłącznie z pól o takich samych typach. Takie
rekordy są stosowane zamiast tablic wtedy, gdy lepiej pozwalają określić
znaczenie wartości znajdujących się w ich polach. Mogą one opisywać np.
współrzędne w dwuwymiarowym lub trójwymiarowym, kartezjańskim układzie
współrzędnych lub liczbę zespoloną:
type
wspolrzedne = record
x,y:real;
end;
Z powyższego przykładu wynika, że jeśli chcemy zadeklarować kilka pól
rekordu o takich samych typach, to możemy ich nazwy rozdzielić przecinkami,
a typ podać tylko jednokrotnie, tak jak ma to miejsce w przypadku zmiennych.
7.Rekordy z wariantami
Rekordy z wariantami pozwalają na pewne sparametryzowanie tego typu
danych. Polem wariantowym zawsze jest ostatnie pole w rekordzie. Oto wzorzec
takiego typu rekordowego:
nazwa_typu_rekordowego = record
nazwa_pola_1: typ_pola_1;
nazwa_pola_2: typ_pola_2;
.
.
.
case selektor: typ_selektora of
10
wartość_selektora_1 : (pole_1: typ_pola_1;
pole_2: typ_pola_2);
wartość_selektora_2 : (pole_1 : typ_pola_1;
pole_2 : typ_pola_2;
pole_3 : typ_pola_3);
end;
Załóżmy, że potrzebujemy opisać rekordem dwie postacie z gry komputerowej:
maga i wojownika. Będą one miały oczywiście wspólne cechy, jak położenie
w przestrzeni i nazwę, ale również będą miały cechy indywidualne, jak miara
siły lub mocy magicznej. Moglibyśmy te postacie opisać jednym typem (nie
licząc pomocniczego typu wyliczeniowego):
type
rodzaj = (mag, wojownik);
postac = record
x,y:real;
nazwa:string[40];
case r:rodzaj of
wojownik: (sila: byte);
mag:(moc_magiczna:word);
end;
8.Zmienne rekordowe
Zmienne typów rekordowych (inaczej zmienne rekordowe lub krótko: rekordy)
deklarujemy tak samo, jak zmienne innych zdefiniowanych przez nas typów.
Istnieje również możliwość zadeklarowania zmiennej rekordowej typu
anonimowego, ale jak w poprzednich przypadkach istnieją problemy
z przekazaniem jej przez parametry. Można natomiast w sekcji const programu
lub podprogramu zadeklarować zmienną zainicjalizowaną typu rekordowego,
według następującego wzorca:
nazwa_zmien:typ_rekordowy = (nazwa_pola_1:wartość; nazwa_pola_2:wartość);
9.Odwoływanie się do pól zmiennej rekordowej
Najprościej do pola zmiennej rekordowej możemy odwołać się według
następującego wzorca:
11
nazwa_rekrodu.nazwa_pola
Jeśli chcemy odwołać się do pola rekordu zagnieżdżonego, to możemy to
uczynić następująco:
nazwa_rekrodu.nazwa_rekordu_zagnieżdżonego.nazwa_pola
Jeśli nie chcemy stosować notacji  kropkowej , to możemy użyć instrukcji
wiążącej with:
with nazwa_rekordu do nazwa_pola_rekordu;
Oczywiście użycie tej instrukcji ma sens jeśli odwołujemy się do większej liczby
pól rekordu. Należy jednak wtedy pamiętać, aby instrukcje odwołujące się do
tych pól umieścić między słowami kluczowymi begin i end występującymi po
słowie kluczowym do. Jeśli pole rekordu jest polem wariantowym, to kiedy się
do niego odwołujemy możemy użyć instrukcji case. Należy zaznaczyć, że
niezależnie od wartości tego pola zmienna zawiera wszystkie pola, które zostały
zadeklarowane w typie rekordowym. Oznacza to, że posługując się rekordami
wariantowymi należy być ostrożnym, gdyż kompilator może nie wychwycić
ewentualnych błędów w odwoływaniu się do pól. Zaletą rekordów z wariantami
jest to, że pozwalają one zaoszczędzić pamięć  kompresując pola wariantowe.
Istnieje również możliwość tworzenia tablic, których elementy są rekordami. Do
pól takich rekordów odwołujemy się według następującego schematu:
nazwa_tablic[indeks]. nazwa_pola
lub z użyciem instrukcji with:
with nazwa_tablicy[indeks] do nazwa_pola;
Poniżej znajdują się kody zródłowe dwóch programów. Pierwszy operuje
rekordem z wariantami opisującym pojedynczego studenta, drugi tablicą
rekordów opisującą osoby.
12
program rekordy;
uses crt;
type
studiujacy = record
imie:string;
nazwisko:string;
numer_indeksu:0..maxlongint;
case status:(absolwent,student,bean) of
absolwent:(ocena_koncowa:real);
student:(srednia_ocen:real);
bean:(punkty_rekrutacji:0..100);
end;
var
rek:studiujacy;
procedure wypelnij(var r:studiujacy);
var
stat:char;
begin
with r do
begin
write('Podaj imię: ');
readln(imie);
write('Podaj nazwisko: ');
readln(nazwisko);
write('Podaj numer indeksu: ');
readln(numer_indeksu);
write('Podaj status (a-absolwent, s-student, b-bean): ');
readln(stat);
case stat of
'a': begin
status:=absolwent;
write('Podaj ocenę końcową: ');
readln(ocena_koncowa);
13
end;
's': begin
status:=student;
write('Podaj średnią ocen: ');
readln(srednia_ocen);
end;
'b': begin
status:=bean;
write('Podaj liczbę punktów rekrutacji: ');
readln(punkty_rekrutacji);
end;
end;
end;
end;
procedure wyswietl(const r:studiujacy);
begin
writeln('Imię: ',r.imie);
writeln('Nazwisko: ',r.nazwisko);
writeln('Numer_indeksu: ',r.numer_indeksu);
case r.status of
absolwent:writeln('Absolwent, ocena końcowa: ',r.ocena_koncowa:2:1);
student:writeln('Student, średnia ocen: ',r.srednia_ocen:2:1);
bean:writeln('Bean, punkty rekrutacyjne: ',r.punkty_rekrutacji);
end;
readln;
end;
begin
clrscr;
wypelnij(rek);
clrscr;
wyswietl(rek);
end.
14
program tablica_rekordow;
uses
crt;
type
osoba = record
imie:string;
nazwisko:string;
wiek:byte;
end;
tablica = array [1..5] of osoba;
tablica1 = array [1..5] of string;
const
tik: tablica1 = ('Anna','Katarzyna','Beata','Joanna','Magdalena');
tnk: tablica1 = ('Kowalska','Zapolska','Orzeszkowa','Konopnicka','Potocka');
tim: tablica1 = ('Andrzej','Edward','Henryk','Ireneusz','Jakub');
tnm: tablica1 = ('Kowalski','Nowak','Sienkiewicz','Żeromski','Dąbrowski');
var
tab:tablica;
procedure wypelnij(var t:tablica; const tik,tnk,tim,tnm:tablica1);
var
i:byte;
begin
randomize;
for i:=low(t) to high(t) do
with t[i] do
begin
if random(2) = 1 then
begin
imie:=tik[random(5)+1];
15
nazwisko := tkn[random(5)+1];
end
else
begin
imie:=tim[random(5)+1];
nazwisko:=tnm[random(5)+1];
end;
wiek:=random(100)+1;
end;
end;
procedure wypisz(const t:tablica);
var
i:byte;
begin
for i:=low(t) to high(t) do
begin
writeln('Imię: ',t[i].imie);
writeln('Nazwisko: ',t[i].nazwisko);
writeln('Wiek: ',t[i].wiek);
readln;
end;
end;
begin
clrscr;
wypelnij(tab,tik,tnk,tim,tnm);
wypisz(tab);
end.
Proszę zwrócić uwagę, w jaki sposób możemy za pomocą tablic elementów typu
string i generatora liczb pseudolosowych rozwiązać problem losowego
(dokładniej: pseudolosowego) zapisu danych do pól rekordu. Warto również
zwrócić uwagę, że powinniśmy unikać przekazywania rekordów do
podprogramów przez wartość.
16
10. Przeciążanie operatorów (tylko Free Pascal)
W materiałach do wykładu na temat podprogramów znajduje się wzmianka
o tym, że środowisko Free Pascala oferuje możliwość przeciążania operatorów,
czyli sprawienia, żeby np. operatory arytmetyczne (+,-, itd.) mogły być
stosowane do typów zdefiniowanych przez programistę. Kilka innych języków
programowania również pozwala na takie rozwiązanie, jednakże wymagają one
użycia programowania obiektowego. Free Pascal umożliwia stosowanie
przeciążania operatorów w programowaniu strukturalnym. Niestety pomysł ten
nie został do końca rozwinięty. Obecne wydania tego środowiska, oraz
prawdopodobnie przyszłe również, pozwalają na przeciążanie operatorów tylko
dla tablic i rekordów. Dokumentacja środowiska pokazuje w jaki sposób
przeciążyć operatory dla rekordów, które modelują liczby zespolone. Poniżej
zostanie pokazany i opisany przykład przeciążania operatora dodawania, tak
aby można było za jego pomocą dodać do siebie dwie macierze. Wcześniej
jednak przedstawiony zostanie w sposób ogólny sposób korzystania
z mechanizmu przeciążania operatorów we Free Pascalu. Aby przeciążyć
określony operator należy napisać specjalny podprogram, który nie jest
funkcją, ani procedurą. Jego definicja rozpoczyna się od słowa kluczowego
operator. Środowisko Free Pascal traktuje instrukcję przypisania jako operator
i jest to jeden z dwóch operatorów jednoargumentowych jaki możemy
przeciążyć. Nagłówek podprogramu przeciążającego taki operator tworzony jest
według następującego schematu:
operator := (a:typ) x:typ;
Nazwa takiego podprogramu jest nazwą operatora (w tym wypadku :=). Po niej
występuje lista argumentów, na której musi znajdować się jeden i dokładnie
jeden argument, o typie dla którego chcemy przeciążyć operator. Po liście
argumentów występuje deklaracja zmiennej wynikowej, której typ musi być
taki sam jak dla argumentu. Do tej zmiennej zapisywany jest wynik działania
podprogramu i pełni ona taką samą rolę jak nazwa funkcji w funkcji. Reszta
podprogramu tworzona jest według tych samych reguł co ciała procedury lub
funkcji. Inny operatorem jednoargumentowym jaki możemy przeciążyć jest
minus zmieniający znak wartości na przeciwny. Free Pascal pozwala również
na przeciążanie dwuargumentowych operatorów arytmetycznych i relacyjnych.
Nagłówki dla podprogramów przeciążających te operatory są definiowane
według następującego wzorca:
operator symbol (x: typ; y:typ2) z:typ;
Symbol oznacza symbol operatora np. +, -, *, typ oznacza typ dla którego
operator jest przeciążany i jest to równocześnie typ argumentu stojącego po
17
lewej stronie operatora. Typ typ2 jest typem drugiego argumentu, który może
być dowolnym typem zmiennej, nawet może być taki sam jak typ. Jest to także
typ operatora stojącego po prawej stronie operatora. W przypadku operatorów
relacyjnych zmienna wynikowa jest zawsze typu boolean. Wywołując
przeciążone operatory należy pamiętać, żeby ich argumenty znajdowały się po
właściwych stronach operatorów, jeśli są różnych typów. Poniżej znajduje się
kod programu, który przeciążą operator dodawania dla macierzy:
program operatory_macierz;
uses
crt;
type
wiersz = array [1..4] of byte;
macierz = array [1..2] of wiersz;
var
m1, m2, m3: macierz;
procedure wypelnij(var m:macierz);
var
i,j:byte;
begin
for i:=low(macierz) to high(macierz) do
for j:=low(wiersz) to high(wiersz) do
m[i,j]:=random(10);
end;
procedure wypisz(const m:macierz);
var
i,j:byte;
begin
for i:=low(macierz) to high(macierz) do
begin
for j:=low(wiersz) to high(wiersz) do
18
begin
for j:=low(wiersz) to high(wiersz) do
write(m[i,j]:3);
writeln;
end;
end;
operator + (const m1,m2:macierz) m:macierz;
var
i,j:byte;
begin
for i:=low(macierz) to high(macierz) do
for j:=low(wiersz) to high(wiersz) do
m[i,j] := m1[i,j] + m2[i,j];
end;
begin
clrscr;
randomize;
wypelnij(m1);
wypelnij(m2);
writeln('Zawartosc pierwszej macierzy');
wypisz(m1); readln;
writeln('Zawartosc drugiej macierzy:');
wypisz(m2);
readln;
m3:=m1+m2;
writeln('Wynik dodawania:');
wypisz(m3);
readln;
end.
Ponieważ większość elementów programu jest bardzo podobna do tych, które
występują w kodzie pierwszego programu demonstrującego działania na
macierzach, to opisane zostaną tylko te, które są nowe. Należy do nich definicja
19
podprogramu przeciążającego operatora dodawania, która występuje po
definicji procedury wypisz. Podprogram ten przyjmuje dwa argumenty tego
samego typu. Są to tablice wielowymiarowe modelujące macierze o rozmiarze
2x4. Zmienna wynikowa ma nazwę m i jest tego samego typu, co oba
argumenty. Ciało tego podprogramu jest bardzo podobne do ciała procedury
suma. Różną się one jedynie tym, że wynik, zamiast do trzeciego argumentu,
jak to ma miejsce w procedurze, przypisywany jest do zmiennej wynikowej.
Dzięki przeciążeniu operatora dodawania, operację sumowania macierzy można
w bloku głównym programu zapisać tym razem po prostu jako m3:=m1+m2.
W ten sam sposób można przeciążyć inne operatory, np. operator mnożenia,
instrukcję przypisania, czy operator różnicy. Więcej informacji na temat
przeciążania operatorów można znalezć w dokumentacji Free Pascala.
20


Wyszukiwarka

Podobne podstrony:
PP1 wyklad
PP1 wyklad 8
PP1 wyklad 3
PP1 wyklad 5
PP1 wyklad 1
PP1 wyklad 2
PP1 wyklad
PP1 wyklad 4
PP1 wyklad 5
PP1 wyklad
PP1 wyklad 4
PP1 wyklad
Sieci komputerowe wyklady dr Furtak
Wykład 05 Opadanie i fluidyzacja
WYKŁAD 1 Wprowadzenie do biotechnologii farmaceutycznej

więcej podobnych podstron