Preštudujte si: Podprogramy
5. Parametre podprogramov
Rovnako ako algoritmy
vďaka možnosti zadávať rôzne vstupné údaje, dokážu riešiť úlohu pre rôzne
vstupné hodnoty, i vhodne napísané podprogramy dokážeme využiť tak, aby
úlohu riešili pre rôzne vstupy. Jeden zo spôsobov, akým možno do podprogramu
„poslať“ hodnoty sme už prezentovali – spracúvali sme údaje uložené
v globálnej premennej.
Ak však chceme, aby
podprogram predstavoval samostatný a nezávislý celok (vďaka čomu by bolo
jeho použitie univerzálne) a aby sme sa nemuseli zaoberať neustálym
sledovaním správaneho obsahu používaných globálnych premenných, potrebujeme
použiť iný aparát.
Funkcie i procedúry
umožňujú využívať tzv. formálne
parametre. Formálny parameter je
špeciálna lokálna premenná, ktorej hodnota sa nastaví pri volaní funkcie
a v momente spustenia tela podprogramu už obsahuje hodnotu
príslušného typu. Počas vykonávania kódu môžeme do nej priraďovať hodnoty
a pracovať s ňou ako s obyčajnou premennou, no po ukončení
podprogramu sa z pamäte uvoľní a zmeny hodnoty sa neprejavia. Všeobecný
zápis vyzerá napr. nasledovne:
procedure Nazov1(par1,par2:typ1;par3:typ2);
{procedure Vypis(a,b:integer;c:string)}
function Nazov2(par1,par2:typ2;par3:typ2):typ3;
{function Vypocet(a,b:integer;c:string):integer}
pričom parametre
rovnakého typu oddeľujeme čiarkou, v prípade použitia premenných viacerých
typov použijeme na oddelenei skupín bodkočiarku.
Volanie podprogramu môže
vyzerať:
vysledok:=Nazov2(a,b,c); {vysledok:=Vypocet(a,10,’test’)}
Napíšte podprogram, ktorý pre zadané n vypíše do prvého
riadku jednu hviezdičku, do druhého dve atď. až po n-tý riadok (v Delphi
vkladajte riadky do Listboxu).
procedure Hviezdy(n:integer);
var i:integer;
riadok:string;
begin
riadok:=’’; {obsahuje
pocet hviezd, ktore treba vypisat}
for i:=1 to n
do begin
riadok:=riadok+’*’; {v kazdom
riadku sa prida jedna *}
Listbox1.Items.Add(riadok); {vypis}
end;
end;
Premenná n obsahuje počet riadkov, ktoré sa majú spracovať
a využíva sa v podprograme len na čítanie. Vykonanie procedúry by sme
mohli zabezpečiť napr. ako Hviezdy(4);.
*
**
*
**
***
*
**
***
****
Úlohu vyriešime dvoma
spôsobmi:
- v hlavnom
programe zavoláme procedúru na vykreslenie trojuholníkov postupne so
zväčšujúcim sa parametrom,
- napíšeme podprogram,
ktorý bude vytvárať strom na základe zadania jeho výšky
begin
for i:=1 to 4
do Hviezdy(i);
end;
Procedúra sa volá najprv
s hodnotou 1 (t.j. vykreslí sa jedna *), potom s parametrom 2
(vykreslí sa trojuholník s prvým riadkom obsahujúcim jeden znak
a druhým dva znaky atď.).
Druhá možnosť je
zaujímavejšia – v procedúre Strom budeme volať procedúru Hviezda vďaka čomu získame pomerne univerzálnu procedúru:
procedure Strom(n:integer);
var i:integer;
begin
for i:=1 to n
do Hviezda(i);
end;
Rovnako ako do procedúr, môžeme i do funkcií
posielať parametre. Tento prístup je pre nás v určitej podobe známy
už z matematiky.
Napíšte
funkciu, ktorá pre dve zadané hodnoty vráti väčšiu z nich. Ak sú rovnaké,
návratová hodnota bude jedna z nich.
function Max(a,b:integer):integer;
begin
if a>b then Max:=a {ak je a vacsie, Max vrati a}
else Max:=b; {inak je b vacsie a Max vrati b}
end;
Do funkcie posielame dve celé čísla
a výsledok bude tiež celočíselný, vo funkcii dôjde k ich porovnaniu
a na základe neho sa do názvu funkcie priradí väčšia hodnota.
Volanie môže mať podobu:
vysledok:=Max(10,20) alebo vysledok:=Max(a,b)
prípadne vysledok:=Max(Max(10,20),30)
pričom jednoznačne najzaujímavejšie je posledné
volanie. V ňom sa najprv nájde hodnota vnorenej funkcie Max(10,20). Výsledok z nej sa potom použije na ďalšej úrovni
a zavolá sa Max(20,30), ktorá vráti skutočný
a správny výsledok.
Napíšte
funkciu, ktorá pre zadané hodnoty a, n vráti an.
Do podprogramov sme doposiaľ posielali len
konkrétne hodnoty, ktoré sa v ich tele spracúvali. Podprogram ich vykonal,
prípadne ak šlo o funkciu, vrátil výsledok. V praxi sa však často
stretneme s prípadmi, keď od podprogramu potrebujeme vrátiť viac ako jednu
hodnotu alebo potrebujeme upraviť obsah premennej, či poľa.
Použitie globálnych parametrov predstavuje obvykle
zbytočné komplikovanie a prekombinovanie kódu, pretože máme
k dispozícii aparát, ktorý nám umožní ovplyvniť iným spôsobom.
Dve triedy
súťažia v zbere papiera. Evidujte odovzdané množstvá jednotlivých žiakov prostredníctvom
poľa. Zistite, ktorá trieda nazbierala viac papiera. Zistite, v ktorej triede
bol vyšší priemerna žiaka (v prípade Delphi načítavajte údaje z Listboxu
a ako jeden z parametrov pošlite do procedúry názov listboxu, pričom
jeho typ bude TListbox).
A tu sa dostávame do situácie, keď pre
načítanie hodnôt do oboch polí použijeme prakticky rovnaký postup (načítavanie
postupnosti ukončené nulou), čo nám ponúka možnosť využiť podprogram. Okrem
toho by sme v rámci podprogramu mohli už pri načítaní zistiť priemery
i celkové nazbierané množstvo.
Vzhľadom na množstvo údajov, ktoré vyžadujeme, nám
funkcia vracajúca ako výsledok jedinú hodnotu, určite nepostačí. Navyše by bolo
vhodné, aby sme si údaje uložené do poľa i zapamätali.
Podprogramy, s ktorými sme sa doteraz stretli
pracovali s parametrami volanými
hodnotou. Do podprogramu vstupovali prostredníctvom lokálnych premenných
hodnoty, s ktorými sa pracovalo, a ktoré sa po ukončení podprogramu
z pamäte uvoľnili.
Pokiaľ chceme, aby sa zmeny v premenných uchovali
i po ukončení podprogramu, potrebujeme ich upraviť na parametre volané adresou. Pamäť pre parametre volané hodnotou sa
vytvára tak, aby bola po ukončení podprogramu uvoľnená. Pokiaľ je parameter
volaný adresou, nemôže byť na jeho pozícii konkrétna hodnota, ale vždy len
názov premennej. Pri inicializácii podprogramu sa preň nevytvorí nové pamäťové
miesto, ale manipuluje sa s tým pamäťovým miestom, na ktorom je uložená
príslušná premenná – t.j. mení sa ako hodnota formálneho parametra v podprograme,
tak i hodnota premennej v tele programu (obe premenné ukazujú na
rovnaké miesto). Po ukončení podprogramu sa pamäťové miesto neuvoľnuje, pretože
pri jeho inicializácii nevzniklo.
Obr. Postup
pri parametroch volaných hodnotou a adresou
Kľúčovým slovom, ktoré definuje parameter ako
volaný adresou je var. Použitie v podprograme
môže vyzerať ako v nasledujúcom príklade:
{na to, aby sme mohli pouzit pole ako parameter
podprogramu,}
{potrebujeme ho definovat ako typ}
var trieda1,trieda2:TZoznam;
sucet1,sucet2:integer; {sucty
za triedu}
priemer1,priemer2:real; {priemery
za triedu}
{parametre pred ktorymi sa nachadza “var” menia v
podprograme hodnoty}
{premennych, ktore su pri volani umiestnene na rovnakych miestach }
procedure Operacia(var trieda:TZoznam;var
suc:integer;var priem:real);
var pocet,hodnota:integer;
begin
pocet:=0;
suc:=0; {inicializacia premennych}
repeat {opakuje,
kym sa nezada hodnota 0}
Writeln(‘Zadaj ziaka c.’,pocet+1); {preco
pocet+1?}
ReadLn(hodnota); {nacita sa hodnota}
if
hodnota>0 then begin {ak je nenulova}
inc(pocet); {zvysi
sa pocet zapojenych ziakov}
trieda[pocet]:=hodnota; {zapamata sa v poli}
suc:=suc+hodnota; {zvysi
sa sucet za triedu}
end;
until
hodnota=0; {koniec nacitavacieho
cyklu}
priem:=suc/pocet; {vypocita
sa priemer}
end;
begin
Operacia(trieda1,sucet1,priemer1); {do
premennej trieda1 sa ulozi}
{zoznam hodnot pre ziakov,
do}
{sucet1 hodnota, ktora je}
{v procedure vedena ako
sucet a}
{detto priemer1}
Operacia(trieda2,sucet2,priemer2); {analogia}
if
sucet1>sucet2 then WriteLn(‘Viac
nazbierala 1. trieda’)
else WriteLn(‘Viac nazbierala 2.
trieda’);
if
priemer1>priemer2 then WriteLn(‘Lepsi
priemer ma 1. trieda’)
else WriteLn(‘Lepsi priemer ma 2.
trieda’);
end;
Procedúra naplní polia
pre prvú i pre druhú triedu, zároveň do premenných sucet1, priemer1 a sucet2, priemer2 získavame prostredníctvom
formálnych parametrov vypočítané hodnoty.
Ošetrite program tak, aby bral do úvahy i rovnosť
výsledkov.
Formálne parametre sú
všetky parametre vystupujúce v tele podprogramu (volané hodnotou
i adresou). Postup popísaný na formálnych parametroch sa
v podprograme aplikuje na objekty určené pri volaní. Označujeme ich ako skutočné parametre. Pre jednotlivé
volania podprogramu môžeme dosadzovať rôzne skutočné parametre a tým je postup,
zostavený a napísaný jedenkrát, použiteľný univerzálne.
Napíšte podprogram, ktorý vymení hodnoty dvoch
premenných.
Napíšte
podprogram, ktorý porovná maximálne hodnoty v dvoch poliach.
Pre zadané pole zistite jeho
minimum a maximum.
Napíšte
podprogram, ktorý pre zadaný názov súboru a meno človeka prehľadá súbor
a vypíše či a akoľkokrát sa v ňom človek nachádza (súbor môže
obsahovať len zoznam mien, napr. návštevníkov budovy).
Napíšte
podprogram, ktorý zaokrúhli číslo na zadaný počet desatinných miest. Číslo
posielajte ako parameter volaný adresou.
Napíšte
funkciu, ktorá pre zadané číslo zistí, či ide o prvočíslo. Odpoveďou bude
hodnota áno/nie (true/false).