- funkce
- definice funkce
- vytváření prototypů
- volání funkce
- parametry funkcí a předávání hodnotou
- násobné parametry
- úkol č. 6
Funkce – programové moduly v C++
C++ poskytuje velikou knihovnu užitečných f-cí, ale skutečné potěšení nastává při psaní vlastních f-cí. Abyste uměli používat f-ce, musíte udělat následující:
- Definici funkce
- Prototyp funkce
- Vyvolat funkci
Jestliže používáte knihovní funkci, tak již byla definována a překompilována. Například knihovní f-ce cstring zahrnuje f-ci strlen() k nalezení délky řetězce. cstring obsahuje i další f-ce, ale takto vyvolaná knihovní f-ce vám poté dovolí kdykoliv vyvolat f-ci strlen() ve vašem programu.
Definice funkce
Funkce můžeme rozdělit na dva druhy – funkce bez návratové hodnoty, funkce s návratovou hodnotou. Funkce bez návratové hodnoty se nazývají f-ce typu void a mají následující obecný tvar:
void jméno_funkce(seznam_parametrů)
{
příkaz(y)
return; // nepovinné
}
Pochopte tuto f-ci tak, že když ji zavoláte, udělá to, co v ní napíšete. seznam_parametrů zde určuje typ a počet parametrů předaných f-ci, tedy jaké hodnoty jí předáte v době volání. Nepovinný příkaz return zde ukazuje na konec f-ce. F-ce bez návratové hodnoty používáme, když chceme například provést nějaký cyklus (neboli f-ce bez návratové hodnoty nám slouží ke zpřehlednění samotného kódu v main). F-ci odtud pak již jen zavoláme a je jedno, zda bude součástí souboru, či si ji vyvoláme jako externí soubor. Například definice f-ce na vytištění deseti pozdravů:
void pozdrav(int n) //funkce bez návratové hodnoty, předává se jí při volání hodnota
{
for (int i=0; i<n; i++)
cout << "Ahoj \n";
cout << "konec";
}
Parametr int n v seznamu znamená, že f-ce pozdrav() očekává při jejím volání hodnotu typu int (proměnná n zde není důležitá).
Funkce s návratovou hodnotou vyžadují použití příkazu return, který se stará o navrácení hodnoty volající f-ci:
jmeno_typu jmeno_funkce(seznam_parametru)
{
příkazy
return hodnota; // hodnota má stejný typ, jako jméno_typu
}
Hodnotou myslíme proměnnou, konstantu či obecněji výraz. Hodnota se vždy reprodukuje na jmeno_typu nebo se na něj konvertuje (je-li definován typ double a navrácená hodnoty je typu int (např. 8), tak se konvertuje int na double (8.0)), návratová hodnota nemůže být pole. Vše ostatní je možné. F-ce se ukončí, jakmile narazí na příkaz return. F-ce ale může mít i více než jeden příkaz return – např. jako alternativy k různým volbám:
int porovnani(int a, int b)
{
if (a > b)
return a; // jel-li a>b, funkce se ukončí zde a navrátí hodnotu a
else
return b; // jinak se f-ce ukončí zde a navrátí se hodnota b
}
Else zde není třeba, ale pomůže lépe pochopit závěr. Následující příklad nám vrací druhou mocninu čísla:
double ctverec(double x)
{
return x * x; // hodnota typu double
}
Jestliže tedy při volání f-ce předáme hodnotu 2, navrátí nám f-ce hodnotu 4.
Vytváření prototypů
Prototyp vytvoříme velmi lehce (nezabývejte se teď tím, kam jednotlivé části f-ce patří). Stačí zkopírovat první řádek definici f-ce a dát za něj středník. Pokud tedy použijeme v programu naše napsané f-ce porovnani a ctverec, jejich prototyp bude vypadat takto:
int porovnani(int a, int b);
double ctverec(double x);
Prototyp popisuje rozhraní f-ce ke kompilátoru, říká mu, jakého typu je návratová hodnota, počet a typ parametrů f-ce. Stále jste možná zvědaví, proč prototyp f-ce kompilátor potřebuje. Kompilátor se díky prototypům seznámí se všemi f-cemi použitými v programu, aniž by je musel „hledat“. Neboli čtení kódu probíhá shora dolů a museli byste bez použití prototypu f-ci definovat před jejím prvním použitím. To není efektivní, protože hlavní f-cí je main. Prototyp tedy oznamuje přítomnost dalších f-cí a odkáže kompilátor na její umístnění. Prototyp f-ce nevyžaduje jména proměnných – seznam typů postačuje.
void pozdrav(int); // vypustit jména proměnných je v prototypech v pořádku
Automatická konverze ovšem nemusí vždy konvertovat hodnotu správně, a to v případě z většího na menší. Například předáváte-li hodnotu 8.54E26 f-ci, která čeká int, nemusí se konvertovat tak velké číslo správně. V tomto případě vás kompilátor varuje před možnou ztrátou dat.
Volání funkce
Pokud chceme zavolat f-ci, není nic lehčího, než napsat její jméno a popřípadě jí předat parametry:
jméno_funkce(seznam_parametrů);
…takže například:
ctverec(5);
Tímto voláním zavoláme f-ci ctverec a předáme jí parametr, v tomto případě číslo 5. Když se podíváme nahoru (jak jsme definovali f-ci ctverec), tak zjistíme, že nám má vrátit hodnotu na druhou, tedy 25:
cout << ctverec(5);
…zobrazí hodnotu 25. A stejně můžeme zobrazit proměnné, které se inicializují až za běhu programu:
int a;
cin >> a; //dejme tomu, že jsme zadali hodnotu 6
cout << ctverec(a); //zobrazí 36
Nyní si ukážeme příklad:
#include <iostream>
using namespace std;
void pozdrav(int); // prototyp: žádná návratová hodnota
double kostka(double x); // prototyp: vrací hodnotu typu double
int main()
{
pozdrav(5); // volání funkce => předá 5ku f-ci pozdrav
cout << "Zadejte cislo: ";
double strana;
cin >> strana;
double prom = kostka(strana); // volání funkce a přiřazení hodnoty do proměnné prom
cout << "Krychle o velikosti strany " << strana <<" metru ma objem ";
cout << prom << " metru krychlovych.\n";
pozdrav(kostka(2)); // ukázka prototypové ochrany
return 0;
}
void pozdrav(int n)
{
for (int i = 0; i < n; i++)
cout << "Slava! ";
cout << "\n";
}
double kostka(double x)
{
return x * x * x;
}
Co se týče prototypové ochrany, není to nic víc, než použití f-ce ve f-ci.
Parametry funkcí a předávání hodnotou
C++ předává obvykle parametry hodnotou. To znamená, že se číselná hodnota parametru předá f-ci, která se přiřadí do nové proměnné.
double prom = kostka(strana);
…a její hlavička funkce byla:
double kostka(double x)
Když se tato f-ce vyvolá, vytváří novou proměnnou typu double, která se nazývá x a přiřadí jí hodnotu 5. Dále jako parametr můžete použít proměnnou stejného jména, jako máte již někde použité. Tedy pokud máte např.:
..
int main()
{
int lek=15;
..
}
double druha (int lek)
...
…tak tyto dvě proměnné jsou úplně rozdílnými proměnnými (lek), poněvadž druhá lek existuje jen uvnitř těla f-ce, tudíž se na ní nemůžete nějak dovolávat a nelze si ji tedy splést s první proměnnou lek. Je to podobné, jako se liší Albana v Kalifornii a Albana v New Yorku.
Násobné parametry
Funkce mohou mít víc než jeden parametr. Ve volání f-ce pouze oddělte parametry čárkou:
kostka('R', 25);
To předává f-ci, kterou si za chvíli definujeme, dva parametry. Když ji deklarujete, postupujte stejně:
void kostka(char c, int n) // 2 parametry
POZOR, pokud definujeme dva parametry stejného typu, nemůžeme je vytvářet jako klasické proměnné:
int a,b; //klasické proměnné
void(int a, b) // nelze
void(int a, int b) // takto je to správně
Stejně tak postupujeme i u vytváření prototypu:
void(int a, int b);
Tak to by bylo všechno. Knihovnu cctype si necháme na později. Možná vyjde jako dodatek (jelikož jsem zjitil, že jsou dodatky důležité, tak jsou nyní již pojmenované jako normální lekce). V příští lekci (pokud to nebude ta knihovna) se budeme zabývat… funkcemi… nečekaně ;) Protože f-ce jsou velké téma! Ještě si musíme ukázat, jak pracují s řetězci a poli. A co nás čeká potom? Dvourozměrná pole, ukazatele, ukazatele na struktury, pole…
Úkol:
Vytvořte program, který bude v int main() obsahovat:
int a;cout << "zadejte číslo: ";
cin >> a;
…a nyní bude následovat menu (počet položek nechám na vás), kde vám ukáže výsledky operací s tímto číslem. Tedy uděláte několik f-cí a každá z nich bude počítat jednu operaci.
Příklad:
zadejte číslo: 5číslo na druhou je: 25
číslo je: jednociferné
…a podobně. Prostě toto vám ukázalo dvě operace (dvě položky) a vy se snažte udělat menu s co nejvíce položkami, co vás napadne udělat s číslem. Každá položka bude ale počítaná ve vlastní f-ci, tedy ne přímo v int main! int main může obsahovat pouze kód uveden výše a jen volání f-cí.