8.10.2002
|
Typ interval
Štruktúrovaný (zložený) typ
POLE
type pole = array[typ_indexu] of typ_prvkov;
- všetky prvky poľa sú rovnakého typu
= pole sa skladá z veľa "jednoduchších"
premenných
- tieto premenné sú prístupné
cez index (selektovanie)
- typ_indexu - ľubovoľný ordinálny typ
- typ_prvkov - ľubovoľný typ
- už neplatí, že celá štruktúra
musí zaberať menej ako 64 KB - ako to bolo v
Turbo pascale
- obmedzenie na veľkosť je len také, aby to
zvládal Windows a ten bez problémov zvládne
dosť veľa MB
- Delphi dovolí zadeklarovať maximálne
2 GB štruktúru, ale Windows má k dispozícii
pre aplikáciu väčšinou len niekoľko MB
array[integer] of byte; - zaberá presne 4
GB - to je už veľa array[byte] of integer; - 1 KB (1024 B) array[char] of boolean; - 0,25 KB (256 B)
zapamätajte si:
|
- 1 B = bajt (8 bitov)
- 1 KB = kilo bajt = 1024 bajtov (trochu viac ako tisíc
bajtov)
- 1 MB = mega bajt = 1024 KB = 1024*1024 B = 1048576
bajtov (trochu viac ako milión bajtov)
- 1 GB = giga bajt = 1024 MB = 1024*1024 KB = 1024*1024*1024
B = 1073741824 bajtov (trochu viac ako miliarda bajtov)
|
- počet prvkov poľa musí byť známy pri
kompilácii
- všetky prvky poľa sa nedajú naraz načítať
ani vypísať jediným príkazom read,
write - treba to rozpísať, napr. pomocou for-cyklu
- Príklad: Program, ktorý o každom prvku
načítaného poľa vypíše, či je jeho
hodnota nad priemerom alebo pod priemerom všetkých
vstupných prvkov, resp. či je to priemer:
jednoduchá práca
s poľom celých čísel:
|
const
max=7;
type
index=1..max;
pole=array[index] of integer;
var
p:pole;
i:index;
s:integer;
t:TextFile;
begin
AssignFile(t,'text.txt'); Reset(t);
for i:=1 to max do read(t,p[i]);
CloseFile(t);
AssignFile(t,'vypis.txt'); Rewrite(t);
s:=0;
for i:=1 to max do inc(s,p[i]);
writeln(t,'Priemer: ',s/max:0:2);
for i:=1 to max do
if p[i]<s/max then writeln(t,p[i],' pod')
else if p[i]>s/max then writeln(t,p[i],' nad')
else writeln(t,p[i],' priemer');
CloseFile(t);
end;
|
niekoľko vylepšení:
- napriek tomu, že si nebudeme v nejakej špeciálnej
konštante (max) pamätať počet prvkov
poľa, môžeme tento program prepísať,
tak aby fungoval správne aj pre zmenený
interval indexov poľa
- použijeme pomocné funkcie low,
high a length:
- tieto fungujú pre typ alebo premennú
typu pole, ale aj pre ľubovoľné ordinálne
typy a premenné
- funkcia high - vráti pre pole
index maximálneho prvku, pre ordinálny
typ vráti maximálnu hodnotu
- funkcia low - vráti pre
pole index minimálneho prvku, pre ordinálny
typ vráti minimálnu hodnotu
- funkcia length funguje len pre pole
a string - pre pole vráti
počet prvkov, pre string momentálnu dĺžku
- všimnite si, že p[i]<s/max
sme nahradili p[i]*length(p)<s
- tento počíta to isté, ale pracuje
len v celých číslach
bez použitia reálnej aritmetiky:
|
type
pole=array[-1..5] of integer; // počet prvkov je 7
var
p:pole;
i,s:integer;
t:TextFile;
begin
AssignFile(t,'text.txt'); Reset(t);
for i:=low(p) to high(p) do read(t,p[i]);
CloseFile(t);
AssignFile(t,'vypis.txt'); Rewrite(t);
s:=0;
for i:=low(p) to high(p) do inc(s,p[i]);
writeln(t,'Priemer: ',s/length(p):0:2);
for i:=low(p) to high(p) do
if p[i]*length(p)<s then writeln(t,p[i],' pod')
else if p[i]*length(p)>s then writeln(t,p[i],' nad')
else writeln(t,p[i],' priemer');
CloseFile(t);
end;
|
Polia ako parametre podprogramov
- formálne parametre typu pole môžu
byť troch typov:
- var-parameter - nevyhradzuje sa žiadna
nová pamäť, ale podprogram priamo
manipuluje so skutočným parametrom
- const-parameter - podobne ako var-parameter,
len sa nám nedovolí v podprograme
to takéhoto poľa priraďovať
- hodnotový parameter - pri volaní
podprogramu sa vytvorí duplikát
celého poľa (rovnakej veľkosti) a vďaka
tomu môžeme modifikovať tento duplikát
(lokálnu premennú) bez toho, aby
sa menil skutočný parameter
- treba dávať pozor na použitie
tohto typu formálneho parametra,
ak je to pole, lebo spomaľuje výpočet,
veľmi míňa pamäť pre lokálne
premenné a často program na tomto
aj hlási chyby
- pri definovaní formálnych parametrov
nesmieme nepriamo definovať nový typ, t.j.
môžeme uvádzať len identifikátory
typov
- typ pole môže byť aj výsledkom funkcie
(typ funkcie musí byť vždy zadaný identifikátorom
typu!)
- túto situáciu si môžeme
predstaviť tak, že volanie funkcie spôsobí:
- vyhradia sa všetky lokálne premenné
(aj hodnotové formálne parametre)
- vyhradí sa jedna špeciálna
lokálna premenná Result,
ktorá je rovnakého typu ako
typ funkcie, teda pole - táto premenná
má zatiaľ nedefinovanú hodnotu
- po skončení výpočtu funkcie
sa "zabudnú" - uvolnia
všetky lokálne premenné, len
hodnota Result sa stane výsledkom
celej funkcie
Príklad: procedúra presun,
ktorá presúva prvky poľa b do poľa a:
|
type
index=1..max;
pole=array[index] of integer;
var
x,y:pole;
procedure presun(var a:pole; b:pole);
begin
a:=b;
end;
...
begin
presun(x,y);
end;
|
- neskôr uvidíme aj parametre typu "otvorené
pole" (open-array)
Napíšeme program, ktorý
- náhodne generuje do poľa X prvky z intervalu
0..n-1
- vypíše pole X
- presunie pole X do poľa Y, zvýši hodnoty
v poli Y o 1 a vypíše pole Y:
procedúry a funkcie s poliami:
|
type
pole=array[1..100] of integer;
function nahodne(n:integer):pole;
var
i:integer;
begin
for i:=low(pole) to high(pole) do
Result[i]:=random(n);
end;
procedure vypis(var t:TextFile; const p:pole);
var
i:integer;
begin
for i:=low(p) to high(p) do write(t,p[i],' ');
writeln(t);
end;
procedure presun(var a:pole; const b:pole);
begin
a:=b;
end;
procedure inc(var a:pole);
var
i:integer;
begin
for i:=low(a) to high(a) do a[i]:=a[i]+1; // system.inc(a[i]);
end;
var
x,y:pole;
t:TextFile;
begin
AssignFile(t,'vypis.txt'); Rewrite(t);
randomize;
x:=nahodne(20);
vypis(t,x);
presun(y,x);
inc(y);
vypis(t,y);
CloseFile(t);
// Memo1.Lines.LoadFromFile('cisla.txt');
end;
|
- všimnite si, že sme vytvorili funkciu inc
na zvýšenie hodnôt prvkov v poli, tým
sme prekryli pôvodný štandardný
identifikátor funkcie inc a preto
ho už v pôvodnom význame používať
nemôžeme (v komentári môžete
vidieť, ako sa tento problém aj tak dá
odstrániť)
Chybné použitie typov:
procedure a(b:array[1..10] of char);
typ formálneho parametra
b nie je identifikátor
procedure x(y:1..10);
typ formálneho parametra
y nie je identifikátor
function f(z:char):array[1..10] of char;
typ funkcie musí byť
zadaný identifikátorom typu
Pole znakov
type pole=array[1..10] of char;
// polia znakov do 255 znakov je možné vypísať
pomocou writeln
var s:pole; begin s:='abcdefghij'; // povolené
priradenie presnej dĺžky ako je deklarovaná, // inak Type mismatch,
napr. s:='abc' writeln(t,s); // povolený výpis
pomocou write(t,identifikátor) end;
- pole znakov sa nedá naraz celé načítať
pomocou read
- výnimka: pole array[0..n] of char Pascal chápe
ako "Null-terminated string", a potom read
vie čítať aj stringy, ktoré sú
kratšie a ukončí ich #0 - neskôr uvidíme
použitie aj takýchto znakových reťazcov
Polia korytnačiek
- n korytnačiek vygenerujeme vedľa seba
na vodorovnej priamke
- každej nastavíme iný uhol
- všetky "naraz" nakreslia kružnicu
pomalá verzia:
|
const
n=50;
var
i,j:integer;
k:array[1..n] of TKor;
begin
for i:=1 to n do
k[i]:=TKor.Create(10*i+10,250,i*15);
for j:=1 to 180 do
for i:=1 to n do begin
k[i].Dopredu(4); k[i].Vpravo(2);
cakaj(1);
end;
end;
|
zrýchlenie programu:
|
const
n=50;
var
i,j:integer;
k:array[1..n] of TKor;
begin
for i:=1 to n do begin
k[i]:=TKor.Create(10*i+10,250,i*15);
k[i].HP:=5;
end;
for j:=1 to 180 do begin
for i:=1 to n do
with k[i] do begin
Dopredu(4); Vpravo(2);
end;
cakaj(1);
end;
end;
|
Poznámka:
- nový pascalovský príkaz with
-
vo vnútri neho sa "prednostne" pracuje s danou korytnačkou
- čo sa stane, ak sa navzájom prehodia dva for
cykly (s i a j)?
- zvládne to aj napr. 100 korytnačiek, ale treba
ich zahustiť (TKor.Create(4*i+10,250,...));
Jednoduchá animácia pomocou korytnačiek:
- predchádzajúci príklad
takto jednoducho pozmeníme:
- cyklus for ... nahradíme nekonečným
while true do ...
- skôr ako sa všetky korytnačky pohnú
o malý krok a otočia, zmažeme obrazovku,
t.j. na obrazovke ostáva len posledná
"stopa"
"krúženie" korytnačiek:
|
const
n=50;
var
i:integer;
k:array[1..n] of TKor;
begin
for i:=1 to n do begin
k[i]:=TKor.Create(10*i+10,250,i*15);
k[i].HP:=10;
end;
while true do begin
zmaz;
for i:=1 to n do
with k[i] do begin
Dopredu(4); Vpravo(2);
end;
cakaj(1);
end;
end;
|
- môžeme s touto ideou rôzne experimentovať:
- korytnačky okrem toho, že prejdú
nejaký malý krok, môžu
popritom niečo kresliť
- každá korytnačka sa môže otáčať
o iný uhol
- môžeme grafickej ploche zmeniť "farbu
pozadia"
zrýchlená verzia:
|
const
n=80;
var
i:integer;
k:array[1..n] of TKor;
begin
for i:=1 to n do begin
k[i]:=TKor.Create(10*i+10,250,i*15);
k[i].HP:=10;
k[i].FP:=clYellow;
end;
while true do begin
zmaz(clNavy);
for i:=1 to n do
with k[i] do begin
Dopredu(54); Dopredu(-50); Vpravo(1+i/n);
end;
cakaj(1);
end;
end;
|
Ďalší príklad
- v tomto príklade korytnačky nevygenerujeme
na jednej priamke, ale rovnomerne na kružnici
- najprv ich všetky vytvoríme v strede
plochy, každú natočíme iným
smerom a potom so zdvihnutým perom prejdú
nejakú rovnakú vzdialenosť
- použili sme vlastnosť korytnačky Smer,
pomocou ktorej môžeme nastavovať absolútne
natočenie korytnačky
korytnačky na kružnici:
|
const
n=60;
var
i:integer;
k:array[1..n] of TKor;
begin
for i:=1 to n do begin
k[i]:=TKor.Create;
with k[i] do begin
HP:=15; FP:=clBlue;
PH; Smer:=360/n*i; Dopredu(100); PD;
Smer:=Smer*2;
end;
end;
while true do begin
zmaz;
for i:=1 to n do
with k[i] do begin
Dopredu(4); Vpravo(2);
end;
cakaj(1);
end;
end;
|
NDÚ:
- v predchádzajúcom príklade
korytnačky nebudú kresliť malý krok,
ale nakreslia úsečky, tak aby boli cyklicky
pospájané
- experimentujte s rôznymi nastaveniami
počiatočných smerov korytnačiek (namiesto
Smer:=Smer*2; skúste
napr. Vpravo(90);
alebo Smer:=Smer*3;)
korytnačky sa naháňajú
- n korytnačiek vygenerujeme na náhodných
pozíciách
- v každom kroku sa každá korytnačka posunie
o 1/100 vzdialenosti k svojej nasledovníčke
(posledná sa posunie k prvej)
naháňačka:
|
const
n=8;
var
i:integer;
k:array[1..n] of TKor;
xx,yy:real;
begin
randomize;
zmaz; // nastavia sa premenné sirka a vyska
for i:=1 to n do begin
k[i]:=TKor.Create(random(sirka),random(vyska));
k[i].HP:=5;
k[i].FP:=random(16777216);
end;
while true do begin
for i:=1 to n do
with k[i] do begin
xx:=k[i mod n+1].X; yy:=k[i mod n+1].Y;
Smer:=Smerom(xx,yy);
Dopredu(Vzd(xx,yy)/100);
end;
cakaj(1);
end;
end;
|
- všimni te si použite i mod n+1
- použili sme novú korytnačiu funkciu Smerom,
ktorá vypočíta absolútny uhol
od korytnačky k nejakému bodu v rovine
- v tomto príklade by bol asi lepší
konečný cyklus namiesto while true do, keďže
po nejakom čase sa všetky korytnačky stretnú
v jednom bode
- program trochu upravíme: korytnačky okrem
toho, že prejdú 1/10 vzdialenosti ku svojej
nasledovníčke, nakreslia k nej aj spojnicu
korytnačky kreslia zaujímavé obrazce:
|
const
n=8;
var
i,j:integer;
k:array[1..n] of TKor;
xx,yy,d:real;
begin
zmaz(clBlack);
randomize;
for i:=1 to n do begin
k[i]:=TKor.Create(random(sirka),random(vyska));
k[i].HP:=2;
k[i].FP:=random(16777216);
end;
for j:=1 to 100 do begin
for i:=1 to n do
with k[i] do begin
xx:=k[i mod n+1].X; yy:=k[i mod n+1].Y; d:=Vzd(xx,yy);
Smer:=Smerom(xx,yy);
dopredu(d); Dopredu(d/10-d);
end;
cakaj(1);
end;
end;
|
- program by fungoval, aj keby sme vyhodili riadok
caka(1); - dokonca by chodil rýchlejšie
|