Anglická verze
logolink

< Zpět na seznam lekcí

Funkce

AlgortimyObsah lekce:

  • Co je to funkce
  • Rozdíl mezi funkcí a procedurou
  • Syntaxe funkce
  • Použití funkcí
  • Použití funkcí s parametry
  • Použití funkcí pro podmínky
  • Předání parametru hodnotou a odkazem
  • Samostatná práce

Co je to funkce

V předchozí lekci jsme si vysvětlili, co jsou to procedury a k čemu je lze použít, u funkcí platí víceméně to samé s pár změnami, které si v této lekci ukážeme.

Funkce je samostatná část programu řešící určitý úkol. Funkce se používají zejména v těchto případech:

  1. chceme-li program zpřehlednit rozložením jeho celého kódu na části (funkce),
  2. opakuje-li se v programu jeden složitější příkaz či posloupnost příkazů,
  3. nějakou část kódu si přejeme používat i v dalších programech.

Bez funkcí se rozhodně neobejdeme, pokud budeme tvořit složitější projekty, protože není rozumné a mnohdy ani možné napsat všechen zdrojový kód do bloku begin..end v hlavním programu.

Rozdíl mezi funkcí a procedurou

Funkce tedy stejně jako procedura může obsahovat libovolný konečný počet příkazů, může používat jak lokální, tak globální proměnné, může přijímat argumenty a používat je pro výpočty a může být zavolána z hlavní části programu nebo jiné funkce/procedury.

Na rozdíl od procedury musí vracet hodnotu. To pro nás znamená výhodu, protože můžeme funkci přímo použít například v podmínkách nebo ve výpočtech bez nutnosti jí nejprve předávat proměnnou pro uložení výsledku a poté tuto proměnnou teprve používat.

Funkce vrací hodnotu zadaného datového typu, což znamená například celé číslo, textový řetězec, nebo hodnotu boolean (lze používat i divočejší typy jako pole, zásobníky atd.), ovšem nelze použít funkci bez této návratové hodnoty jako v jiných programovacích jazycích (některé umožňují použít tzv. prázdnou hodnotu).

Syntaxe funkce

Syntaxe každé funkce musí vypadat následovně:

Obecná syntaxe funkce
Function název (parametry funkce):návratová hodnota;		//parametry jsou volitelné
var proměnné	//volitelná deklarace proměnných pro funkci
begin
  programový kód funkce
  název:=hodnota;	//přiřazení návratové hodnoty
end;

Každá funkce musí začínat klíčovým slovem function, za kterým následuje její název, případně lze uvést parametry do závorky za funkcí. Novinkou oproti procedurám je zbytek prvního řádku, kde ještě přidáváme dvojtečku a za ní typ návratové hodnoty (integer, string, boolean, …). Tato hodnota musí být na konci funkce vrácena zpět tak, aby mohla být použita nadřazenou částí programu, která tuto funkci zavolala.

Následuje nepovinný řádek s lokálními proměnnými, klíčové slovo begin a programová část funkce, která obsahuje všechny příkazy a výpočty.

Další novinkou je předposlední řádek, kdy určujeme, jaká hodnota má být vrácena. Zde přiřadíme funkci její návratovou hodnotu (použijeme funkci jako proměnnou se stejným názvem). Návratová hodnota může být přiřazena přímo například číslem nebo textem, nebo ji lze přiřadit z proměnné. Ovšem je nutné dodržet typ, který jsme zvolili v prvním řádku, jinak dojde k chybě.
Pozn: přiřazení návratové hodnoty funkci nemusí být poslední provedený příkaz, lze přidat příkazy i za tento řádek.

Definice funkce končí klíčovým slovem end, za kterým následuje středník! Pozor, zde se často dělá chyba – na středník se zapomíná.

Použití funkcí

Ukažme si tedy na úvod nějakou hodně jednoduchou funkci pro pochopení principu návratové hodnoty. Pro zjednodušení zdrojových kódů nebude uváděna hlavička programu s jeho názvem a použitými knihovnami, protože zde nic měnit nebudeme.

Funkce pro vypsání pozdravu
function vratpozdrav:string;
begin
  vratpozdrav:='Ahoj';
end;

begin
  writeln(vratpozdrav);
  readln;
end.

Vidíme, že byla definována funkce s názvem vratpozdrav, která nedělá nic kromě toho, že vrátí textový řetězec Ahoj. Následně tuto funkci použijeme v hlavní části programu a necháme vrácenou hodnotu přímo vypsat do konzole. Příkaz writeln(vratpozdrav) tedy udělá to samé jako bychom napsali writeln(‘Ahoj‘). Celý program do konzole vypíše pozdrav Ahoj a poté počká na stisknutí enteru, aby se ukončil (pokud bychom nepřidali řádek readln, tak bychom si pozdrav ani nepřečetli, protože by se program ihned po jeho vypsání ukončil).

Všimněme si, že pokud funkce nevyžaduje žádné parametry, není nutno zapisovat za její název prázdné závorky.

Pokud bychom chtěli odpovídající program napsat pomocí procedur, museli bychom jej změnit takto:

Procedura pro vypsání pozdravu
var pozdrav:string;

procedure vratpozdrav;
begin
  pozdrav:='Ahoj';
end;

begin
  vratpozdrav;
  writeln(pozdrav);
  readln;
end.

Vidíme, že musela být navíc zavedena globální proměnná, která bude po celý zbytek programu zabírat místo v paměti.

Nyní si můžeme ukázat rozšířený příklad, kde použijeme lokální proměnnou například pro uchování výsledku nějakého výpočtu a tuto proměnnou vrátíme.

Funkce pro výpočet fiktivního vzorce
function Spocitej:integer;
var soucet:integer;
begin
  soucet:=45+54*2;
  Spocitej:=soucet;
end;

begin
  writeln(Spocitej);
  readln;
end.

V tomo příkladu jsme vytvořili funkci Spocitej, která uloží výsledek fiktivního výpočtu do proměnné soucet a ta je poté vrácena. V hlavní části programu je výsledek funkce vypsán do konzole.

Použití funkcí s parametry

Příklad můžeme dále vylepšit přidáním parametrů pro funkci.

Vylepšení funkce o parametry
var a,b:integer;

function Spocitej(var a,b:integer):integer;
var soucet:integer;
begin
  soucet:=a+b;
  Spocitej:=soucet;
end;

begin
  a:=40;
  b:=50;
  writeln(Spocitej(a, b));
  readln;
end.

Nyní vidíme, že funkce Spocitej vyžaduje dva parametry – celá čísla, která sečte a vrátí výsledek. Byly vytvořeny dvě globální proměnné a a b, které jsou předávány jako parametry. Bohužel jazyk Pascal na rozdíl od jiných programovacích jazyků neumožňuje předávat hodnoty přímo způsobem Spocitej(40, 50), je nutno je prvně uložit do proměnných.

Tyto příklady byly pouze ilustrační, neřešily žádný konkrétní úkol. V další části lekce se podíváme na příklady, které již lze použít v reálných programech.

Použití funkcí pro podmínku

Návratová hodnota je velikou výhodou hlavně v okamžiku, kdy potřebujeme ověřit jistou podmínku výsledku, ale zároveň potřebujeme teprve tento výsledek spočítat. Díky funkcím pro tento účel nepotřebujeme žádné další proměnné, protože lze funkci přímo vložit do podmínky, pokud vrací odpovídající hodnoty boolean.

Nyní se podíváme na příklad, který sečte a vynásobí dvě čísla a pokud budou oba výsledky menší než 100, tak vypíše určitou hlášku.

Použití funkcí pro podmínku
var a,b:integer;

function Vynasob(var x,y:integer):boolean;
begin
  if (x*y<100) then
    Vynasob:=true
  else
    Vynasob:=false;
end;

function Secti(var x,y:integer):boolean;
begin
  if (x+y<100) then
    Secti:=true
  else
    Secti:=false;
end;

begin
  a:=8;
  b:=11;
  if (Secti(a,b) AND Vynasob(a,b)) then
    writeln('Soucet i soucin jsou mensi nez 100.');
  readln;
end.

V tomto příkladu byly definovány dvě funkce Vynasob a Secti, které vrací hodnoty typu boolean. Funkce vrátí hodnotu true v případě, že součin a součet zadaných parametrů jsou menší než 100. V hlavní části programu nejprve inicializujeme proměnné a poté použijeme podmínku na ověření, zdali jsou součet i součin menší než 100. V případě, že jsou, je vypsána hláška – pokud použijeme hodnoty 8 a 11, hláška bude vypsána.

Vidíme tedy, že funkce lze libovolně používat místo boolean proměnných a spojovat je logickými spojkami. Toto je jejich hlavní rozdíl oproti procedurám a také jejich největší výhoda.

Předání parametru hodnotou a odkazem

Parametry funkcím mohou být předávány dvěma způsoby, buď hodnotnou, nebo odkazem. Pokud budeme předávat parametr hodnotu, tak si funkce vezme hodnotu z proměnné uvedené v závorce při jejím volání a touto hodnotou inicializuje svou lokální proměnnou. Jakékoli změny, které s lokální proměnnou provedeme, nebudou mít žádný vliv na proměnnou, kterou jsme vložili do závorky při volání funkce.

Ovšem může nastat situace, kdy bychom potřebovali právě tuto vloženou proměnnou změnit uvnitř funkce. Toto řešení se může hodit při volání funkcí z jiných funkcí, kde by mohlo být použití globální proměnné problematické.

Rozdíl si ukážeme na následujících jednoduchých příkladech, kde místo funkcí využijeme procedury, u kterých funguje předávání parametrů naprosto stejně (abychom nemuseli řešit návratové hodnoty).

  • Předání parametru hodnotou:
Předání parametru hodotou
var cislo:integer;

procedure predanihodnotou(a:integer);
begin
  writeln(a);
  a:=10;
  writeln(a);
end;

begin
  cislo:=5;
  predanihodnotou(cislo);
  writeln(cislo);
  readln;
end.
funkce

Můžeme vidět, že po předání proměnné cislo do procedury je v ní obsažena hodnota 5. Procedura přiřadí proměnné hodnotu 10, která je následně vypsána. Ovšem po návratu zpět do hlavní části programu vidíme, že proměnná cislo stále obsahuje hodnotu 5. Jak je to možné? Jde o to, že jsme v definici parametrů pro proceduru neuvedli před proměnnou a klíčové slovo var. Procedura si tudíž pro tento parametr vytvoří svou vlastní lokální proměnnou a veškeré změny probíhají jen u ní. Při návratu do hlavní části je lokální proměnná již nepřístupná a je dále pracováno s proměnnou cislo, která nebyla změněna.

  • Předání parametru odkazem:
Předání parametru odkazem
var cislo:integer;

procedure predaniodkazem(var a:integer);
begin
  writeln(a);
  a:=10;
  writeln(a);
end;

begin
  cislo:=5;
  predaniodkazem(cislo);
  writeln(cislo);
  readln;
end.
funkce

Přidáním klíčového slova var se situace změnila. Vidíme, že hodnota proměnné cislo byla změněna uvnitř funkce. Funkci jsme totiž nepředali hodnotu proměnné, nýbrž místo v paměti, kde je proměnná uložena. Funkce poté s tímto místem pracovala a veškeré změny byly prováděny s proměnnou cislo. Proto po návratu do hlavní části programu byla vypsána hodnota 10.

Program na součet ceny zboží

Předávání parametru odkazem si ukážeme ještě na dalším příkladu. Představme si, že budeme psát program pro nějaký obchod. Budeme mít zadány ceny určitých výrobků (pro zjednodušení například 3 výrobků) bez DPH a budeme potřebovat prvně sečíst všechny ceny bez DPH a poté teprve všechny ceny s DPH (budeme počítat s daní 20 %).

Vytvoříme si funkci, která sečte hodnoty, vypíše výsledek a zároveň hodnoty navýší o daň. Při druhém zavolání tudíž bude sčítat již zdaněné hodnoty. Danění položek bude probíhat až po součtu, takže při druhém zavolání funkce již navýšení nebude vadit. Samozřejmě je to zbytečné plýtvání časem procesoru, jedná se jen o příklad použití předání parametru odkazem.

Funkce pro součet ceny zboží
var a,b,c:extended;

function sectiazdan(var a,b,c:extended):extended;
begin
  sectiazdan:=a+b+c;
  a:=a*1.2;
  b:=b*1.2;
  c:=c*1.2;
end;

begin
  a:=100;
  b:=200;
  c:=300;
  writeln('Soucet nezdanenych polozek: ', sectiazdan(a,b,c):0:0);
  writeln('Soucet zdanenych polozek: ', sectiazdan(a,b,c):0:0);
  readln;
end.

V programu bylo nutno použít veškeré proměnné typu extended, protože ve funkci sectiazdan probíhá násobení číslem 1,2. Ve výpisu hodnot do konzole jsme za hodnotu funkce přidali ještě zápis :0:0, který znamená, že číslo má být vypsáno s nulovým počtem desetinných míst. Pokud bychom tento zápis nepřidali, vypadal by výsledek takto:

funkce

Samostatná práce

Vše podstatné u funkcích již víte, proto se můžete pustit do tvorby vlastních funkcí. Následující příklady by šly rozhodně napsat také jako procedury, zkuste pouvažovat, jaké by to mělo výhody nebo nevýhody – uvažujte počet použitých proměnných globálně a lokálně a také počet nutných kroků pro docílení stejného výsledku.

Funkce JeVetsi

Napište funkci JeVetsi, která bude mít za úkol porovnat čísla zadané v parametru a vrátí boolean hodnotu true v případě, že bude první zadané číslo větší. V případě, že bude větší druhé číslo, vrátí hodnotu false.

Funkce Maximum

Napište funkci Maximum, která bude požadovat libovolně veliké pole celých čísel jako parametr a bude vracet celočíselnou hodnotu. Tato funkce projde pole a vrátí nejvyšší nalezenou hodnotu.
Pozn.: pole inicializujte náhodnými čísly 1 až 50.

Funkce Minimum

Obdoba předchozí funkce, ovšem bude vracet nejnižší nalezenou hodnotu.
Pozn.: pole inicializujte náhodnými čísly 1 až 50.

Funkce Prumer

Napište funkci Prumer, která bude požadovat libovolně veliké pole celých čísel jako parametr. Tato funkce projde pole a spočítá průměr všech položek. Nezapomeňte, že průměr nemusí být celočíselný a neměl by být příliš nepřesný (ideálně zaokrouhlen na 2 desetinná místa).
Pozn.: pole inicializujte náhodnými čísly 1 až 50.

Otázky

  1. Jaký je rozdíl mezi funkcí a procedurou? Uveďte příklady využití.
  2. Jaká je základní syntaxe funkce?
  3. Jaký je rozdíl mezi předáváním parametrů odkazem a hodnotou? Uveďte příklady využití.
  4. Lze funkci použít uvnitř podmínky? Uveďte příklad s využitím logických spojek.
webdesign, xhtml, css, php - Mgr. Michal Mikláš