Funkce v C a metody v C# Kapitola pojednává o funkcích v C a metodách v C#. Uvádí obecnou definici funkcí/metod a rozebírá možnosti komunikace funkce/metody s jinými funkcemi/metodami: přes návratovou hodnotu, parametry a globální proměnné. Zmíněny jsou rekurzivní a přetížené funkce/metody. Látka je doplněna řadou programů v jazycích C a C#. Klíčové pojmy: Funkce/metoda, definice funkce/metody, volání funkce/metody, návratová hodnota funkce/metody, parametry funkce/metody, rekurzivní a přetížené funkce/metody.
Pojem funkce/metody Funkce/metoda je pojmenovaná množina příkazů, kterou lze volat z jiných částí programu. Funkce/metoda je samostatná jednotka, která může být samostatně vytvářena a upravována V jazyku C se používá pojem funkce, v jazyku C# pojem metoda. Výhody funkcí/metod Šetří paměť (množina příkazů je zapsaná pouze jednou) Zpřehledňují program Funkce main/Main Každý C program obsahuje právě jednu funkci main. Každá konzolová aplikace C# obsahuje právě jednu funkci Main. Touto funkcí začíná vykonávání programu. Dělení funkcí/metod standardní uživatelské podpůrné a nadstavbové Knihovní funkce/metody jsou definovány normou jazyka - knihovní funkce deklarace je v jazyku C popsána v hlavičkových souborech nemáme k dispozici jejich zdrojový kód Příklady: scanf, printf, getchar, putchar, sin, cos, tan,…
2.11.11
Funkce v C a metody v C#
1/39
Tvorba vlastních funkcí/metod
v C: Před mainem uvedeme prototyp, za mainem definici funkce Před mainem uvedeme celou definici funkce.
v C#: Pro jednoduché programy budeme funkce definovat ve stejné třídě jako funkci Main() před Main(), nebo za Main(): using System; class Program{ static void Vypis() { Console.WriteLine("Otec"); } static void Main(){ Vypis(); } }
Prototyp funkce v C Prototyp funkce je hlavička, ukončená středníkem. Obecný tvar prototypu: Návratový-typ jméno(seznam parametru);
Překladač potřebuje znát tyto informace, aby mohl správně zpracovat volání funkce.
Obecná definice funkce/metody Obecný formát funkce: Navratovy-typ jmeno(seznam parametru) // hlavička { Prikazy; // Tělo funkce }
Návratový typ funkce/metody Návratový typ je typ dat vracených funkcí pomocí příkazu return. Určuje typ vracené hodnoty (lze použít void – prázdný typ, pokud funkce nic nevrací). Návratová hodnota funkce/metody Návratová hodnota je výsledkem výrazu za return. return výraz_vhodného_typu;
2.11.11
Funkce v C a metody v C#
2/39
Příklad definice funkce s návratovou hodnotou:
v C: int isqr(int i){return i * i;}
v C#: static int isqr(int i) { return i * i; }
V C# před návratovým typem uvádíme ještě klíčové slovo static . Volání funkce s využitím její návratové hodnoty:
v C: #include <stdio.h> int isqr(int i){return i * i;} int main(){ int i; for(i=2;i<10;i++) printf("%d %d\n",i,isqr(i)); }
v C#: static int isqr(int i) { return i * i; } static void Main(){ int i; for (i = 2; i < 10; i++) Console.WriteLine("{0} {1}", i, isqr(i)); }
Uvedený program vypíše tabulku čísel od 2 do 9 a jejich druhé mocniny. To je ukázka, jak jednu funkci můžeme volat v rámci druhé funkce – zde funkci isqr voláme ve funkci Console.WriteLine. Jiné volání funkce může být přes proměnnou stejného typu, jako je návratový typ volané funkce:
VC int isqr(int i){return i * i;} int main(){ int i,i2; for(i=2;i<10;i++){ i2=isqr(i); printf("%d %d\n",i,i2); }}
V C# může být návratovou hodnotou řetězec 2.11.11
Funkce v C a metody v C#
3/39
class Program { static string vrat(int i) { string[] mesta={"Praha","Brno","Pardubice","Hradec Králové"}; return mesta[i]; } static void Main() { for(int i=0;i<4;i++) Console.WriteLine(vrat(i)); Console.ReadLine(); }}
Příkaz return Každá funkce s návratovou hodnotou musí uvnitř své příkazové části obsahovat příkaz return, který: ukončí činnost funkce a předá řízení bezprostředně za místem, z něhož byla funkce volána vrátí hodnotu výrazu za return do volající jednotky Funkce může obsahovat i více příkazů return. Příklad: Vyhodnocení testu zadaného čísla: nula/různé od nuly Načtení čísla proběhne ve funkci. V mainu/Mainu je funkce zavolaná, otestovaná její návratová hodnota a podle výsledku vypsaný odpovídající text. Funkce je zavolaná v podmínce příkazu if a její návratová hodnota je porovnaná s konstantou 0. Jestliže funkce vrátí hodnotu různou od nuly, vypíše se text: ruzne od nuly, jinak se vypíše: zadana nula.
v C: float funkce(){ float a; printf("napis cislo\n"); scanf("%f", &a); return a; } int main(){ if(funkce())printf("ruzne od nuly"); else printf("zadana nula"); getch(); }
v C#: class Program{
2.11.11
Funkce v C a metody v C#
4/39
static float funkce() { float a; Console.WriteLine("napis cislo"); a=(float)Convert.ToDouble(Console.ReadLine()); return a; } static void Main(){ if (funkce()!=0) Console.WriteLine("ruzne od nuly"); else Console.WriteLine("zadana nula"); }}
Řešený příklad: Zadávání dvou čísel a výpis jejich součtu, dokud jako první operand nezadáme nulu
v C: float a,b; int cteni(){ scanf("%f",&a); if(!a)return 1; scanf("%f",&b); return 0; } int main(){ do{ if(cteni())break; printf("%f\n",a+b); }while(1); return 0; }
v C#: class Program{ static float a, b; static int cteni() { Console.WriteLine("napiš první číslo"); a = (float)Convert.ToDouble(Console.ReadLine()); if (a==0) return 1; Console.WriteLine("napiš druhé číslo"); b = (float)Convert.ToDouble(Console.ReadLine()); return 0; } static void Main(){ do { if (cteni()==1) break; Console.WriteLine("Součet je: {0}", a + b); } while (true); } }
2.11.11
Funkce v C a metody v C#
5/39
Pojmy deklarace a definice funkce v C Definice funkce je kompletní napsání funkce (její hlavičky a těla). Deklarace funkce je uvedení jejího prototypu (překladači to stačí).
Lokálními a globálními deklarace Globální deklarace jsou uvedeny nad všemi funkcemi Lokální deklarace jsou uvedeny v některé funkci. Mají-li mít funkce/metody společné proměnné, jedenou z možností je deklarovat je jako globální. Příklad: Výpočet zadaného výrazu Vytvořte program, který načte výraz ve tvaru: operand1 operátor operand2 V mainu/Mainu se vyhodnotí operátor a podle zadaného operátoru se zavolá funkce soucet, nebo soucin, která vypíše hodnotu zadaného výrazu. Čtení a výpočet jsou zacyklené, dokud budeme zadávat platné operátory: +, nebo *.
v C: float a,b; char c; cteni(){ scanf("%f %c %f",&a,&c,&b); } soucet(){ printf("%f\n", a+b); } soucin(){ printf("%f\n", a*b); } int main(){ do{ cteni(); switch(c){ case '+':soucet();break; case '*':soucin();break; } }while(c=='+' || c=='*'); return 0;}
v C#: class Program{ static float a, b; static char c; static void cteni(){ string []vyraz = new string[3];
2.11.11
Funkce v C a metody v C#
6/39
Console.WriteLine("napiš výraz: "); vyraz = Console.ReadLine().Split(' '); a = (float)Convert.ToDouble(vyraz[0]); c = Convert.ToChar(vyraz[1]); b = (float)Convert.ToDouble(vyraz[2]); } static void soucet(){ Console.WriteLine("{0}", a+b); } static void soucin(){ Console.WriteLine("{0}", a*b); } static void Main(){ do{ cteni(); switch(c){ case '+':soucet();break; case '*':soucin();break; } } while(c=='+' || c=='*'); }}
Zastínění globální proměnné Jestliže ve funkci/metodě deklarujeme lokální proměnnou, která má stejné jméno, jako globální proměnná, dochází k tzv. zastínění globální proměnné lokální proměnnou. Tento jev způsobí, že pokud se budeme na proměnnou odvolávat pouze jejím identifikátorem, bude ve funkci použita lokální proměnná. Přístup ke globální proměnné je v C pomocí operátoru čtyřtečka a v C# pomocí názvu třídy, Situaci objasní následující příklad: Zadání: Vytvořte program, který bude obsahovat: definici globální proměnné a typu int s hodnotou 10 funkci fce, která bude obsahovat definici lokální proměnné a typu int s hodnotou 20 a její výpis funkci main/Main, která bude obsahovat definici lokální proměnné a typu int s hodnotou 30 , její výpis a volání fce
v C: int a=10; fce(){ int a=20; printf("Lokalni ve funkci: %d\n",a); } int main(){ int a=30;
2.11.11
Funkce v C a metody v C#
7/39
printf("Lokalni v mainu: %d\n",a); fce(); return 0; }
v C#: class Program{ static int a=10; static void fce(){ int a=20; Console.WriteLine("Lokalni ve funkci: {0}", a); } static void Main(){ int a=30; Console.WriteLine("Lokalni v mainu: {0}", a); fce(); }}
Otázky: 1. Jak získat v mainu/Mainu hodnotu lokální proměnné a ve funkci fce? 2. Jak v mainu/Mainu a ve funkci vypsat obsah globální proměnné a? Řešení otázky 1: Jak získat v mainu/Mainu hodnotu lokální proměnné a ve funkci fce? Funkce může hodnotu proměnné a vrátit do mainu/Mainu jako návratovou hodnotu.
v C: int a=10; int fce(){ int a=20; printf("Lokalni ve funkci: %d\n",a); return a; } int main(){ int a=30,b; printf("Lokalni v mainu: %d\n",a); b=fce(); printf("Lokalni ve funkci, vypise v mainu : %d\n",b); return 0;}
v C#: class Program{ static int a = 10; static int fce() { int a = 20; Console.WriteLine("Lokalni ve funkci: {0}", a);
2.11.11
Funkce v C a metody v C#
8/39
return a; } static void Main(){ int a = 30, b; Console.WriteLine("Lokalni v mainu: {0}", a); b = fce(); Console.WriteLine("Lokalni ve funkci, vypise se v mainu : {0}", b); } }
Řešení otázky 2: Jak v mainu/Mainu a ve funkci vypsat obsah globální proměnné a?
v C: int a=10; int fce(){ int a=20; printf("Globalni : %d\n",::a); return a; } int main(){ int a=30,b; printf("Globalni : %d\n",::a); b=fce(); printf("Lokalni ve funkci, vypise v mainu : %d\n",b); return 0; }
Operátor čtyřtečka (2 dvojtečky) umožňuje přístup ke stejnojmenné globální proměnné, zastínění lokální proměnnou.
v C#: class Program{ static int a = 10; static int fce(){ int a=20; Console.WriteLine("Globalni : {0}", Program.a); return a; } static int Main(){ int a=30,b; Console.WriteLine("Globalni : {0}", Program.a); b=fce(); Console.WriteLine("Lokalni ve funkci, vypise v mainu : {0}", b); return 0; }}
Chceme-li v programu v C# ve funkci vypsat hodnotu globální proměnné, zastíněné stejnojmennou lokální proměnnou, musíme před její název uvést název třídy (zde Program) a operátor tečka (.). Globální proměnné jsou společné pro všechny části programu, jsou „viditelné“ ze všech 2.11.11
Funkce v C a metody v C#
9/39
funkcí. Používáním globálních proměnných se můžete dostat do problémů. Pokud začnete hojněji používat funkce, ztratíte v globálních proměnných přehled a jedna funkce přepíše proměnnou jiné funkce. Proto je vhodné, aby funkce používaly na své interní záležitosti lokální proměnné. Příklad: Zastínění globálních proměnných a,b lokálními proměnnými. float a=1,b=1; // globální proměnné void fce1(){ float a=2,b=2; // lokální ve fce1 printf("fce1: %.2f %.2f\n", a,b); } void fce2(){ printf("fce2: %.2f %.2f\n", a,b); } int main(){ float a=3,b=3; // lokální v mainu fce1(); fce2(); printf("main: %.2f %.2f\n", a,b); return 0; }
V tomto programu jsou ve fce1 a v mainu globální proměnné a,b zastíněné lokálními proměnnými a,b. Přístup k zastíněnému globálnímu identifikátoru v C Pomocí operátoru ::
Parametry funkcí a způsob jejich předávání Parametry slouží k předávání hodnot mezi volající a volanou funkcí. Parametry jsou lokální proměnné, jejichž rozsahem platnosti je blok, tvořící tělo funkce. Parametry se uvádí v kulatých závorkách za jménem funkce. V definici a deklaraci funkce se nazývají formální, ve volání skutečné. Skutečné parametry nazýváme též argumenty. V C/C++ jsou 3 možnosti předávání parametrů funkci hodnotou odkazem ( v C++) adresou To se projeví tím, jak je uvedený parametr v definici (respektive i ve volání) funkce.
2.11.11
Funkce v C a metody v C#
10/39
V C# jsou 3 možnosti předávání parametrů funkci (volání metody): hodnotou odkazem ( ref) jako výstupní (out)
Předávání parametrů hodnotou: Hodnoty skutečných argumentů jsou předány do zásobníku. Formální argumenty se odkazují na odpovídající místa v zásobníku (kopie skutečných argumentů). Změna hodnoty formálního parametru se nepromítne do změny hodnoty argumentů Problém vzniká v okamžiku, kdy potřebujeme, aby funkce vrátila více než jednu hodnotu. Řešení pomocí globální proměnné se nepovažuje za vhodné (vedlejší účinky) Při předávání parametrů hodnotou se příslušný parametr chová pro funkci jako vstupní (funkce ho může převzít a pracovat s ním), ne však jako výstupní (funkce nemůže jeho změnu předat do volající jednotky). Funkce fce převezme z mainu hodnotu proměnné a vypíše ji:
v C: void fce(int a){ printf("Lokalni v mainu : %d\n",a); } int main(){ int a=30; fce(a); fce(40); return 0; }
v C#: class Program{ static void fce(int a) { Console.WriteLine("Lokalni v mainu : {0}", a); } static int Main() { int a = 30; fce(a); fce(40); return 0;
2.11.11
Funkce v C a metody v C#
11/39
}}
Je-li parametr předáván hodnotou, můžeme funkci volat s konstantní hodnotou parametru (viz. volání: fce(40);). Ve funkci fce nesmí být deklarovaná lokální proměnná a – viz následující příklad: void fce(int a){ int a=10; printf("Lokalni v mainu : %d\n",a); }
Překladač by vypsal chybu: error C2082: redefinition of formal parameter 'a'
Změní-li funkce hodnotu parametru, změna se nepřenese do volající jednotky. void fce(int a){ printf("Lokalni v mainu : %d\n",a); a=10; } int main(){ int a=30; fce(a); printf("Lokalni v mainu : %d\n",a); fce(40); printf("Lokalni v mainu : %d\n",a); return 0; }
Vypíše se: Lokalni Lokalni Lokalni Lokalni
v v v v
mainu mainu mainu mainu
: : : :
30 30 40 30
Předávání parametrů odkazem v C: Jestliže uvedeme před formálním parametrem a & ,změna proměnné a se přenese z funkce do mainu. Chceme-li změnu parametru přenést z volané do volající funkce (použít parametr jako výstupní), musíme parametr předávat odkazem, nebo adresou. Předávání odkazem bylo zavedeno až v C++ a v C++ se ho doporučuje používat, neboť je jednodušší než předávání adresou a nepracuje s ukazateli. Při předávání parametru odkazem uvádíme před příslušným formálním parametrem znak &.
& před formálním parametrem nám umožní přenést hodnotu z funkce do volající jednotky (mainu).
2.11.11
Funkce v C a metody v C#
12/39
main převezme z fce hodnotu parametru a vypíše ji: //Předávání parametrů odkazem void fce(int &a){ a=20; } int main(){ int a=30; fce(a); printf("Lokalni ve funkci : %d\n",a); return 0; }
Má-li funkce měnit hodnotu parametru, musí být parametry předávané odkazem. void fce(int &a){ printf("Preneseno a=10; } int main(){ int a=30; fce(a); // volání printf("Preneseno a=40; fce(a); // volání printf("Preneseno }
z mainu do funkce : %d\n",a);
funkce z funkce do mainu : %d\n",a); funkce z funkce do mainu : %d\n",a);
Program vypíše: Preneseno Preneseno Preneseno Preneseno
z z z z
mainu do funkce funkce do mainu mainu do funkce funkce do mainu
: : : :
30 10 40 10
v C#: class Program { static void Fce(ref int a) { Console.WriteLine("Hodnota z Mainu {0}",a); a = 10; } static void Main() { int a=30; Fce(ref a); Console.WriteLine(a); a = 40; Fce(ref a); } }
Předávání parametrů adresou: Používá se v C, má-li funkce změnit hodnotu parametru. 2.11.11
Funkce v C a metody v C#
13/39
V definici funkce je parametrem ukazatel a při volání je skutečný parametr adresa proměnné. void fce(int *a){ *a=20; } int main(){ int a=30; fce(&a); printf("Funkce meni parametr : %d\n",a); return 0; }
Pole jako parametr funkce U formálního parametru musíme za identifikátorem pole prázdné hranaté závorky, u skutečného parametru stačí uvést název pole.
1. Výpis jednorozměrného pole znaků v C: void vypis(char pozdrav[]){ puts(pozdrav); } int main(){ char pozdrav[]="Dobry den"; // Voláme funkci vypis vypis(pozdrav); return 0; }
v C#: class Program { static void vypis(char []pozdrav){ Console.WriteLine(pozdrav); } static int Main(){ char []pozdrav="Dobrý den".ToCharArray(); // Voláme funkci vypis vypis(pozdrav); return 0; }} Zde je vhodné místo pole znaků použít řetězec: class Program { static void vypis(string pozdrav){ Console.WriteLine(pozdrav); } static int Main(){ string pozdrav="Dobrý den";
2.11.11
Funkce v C a metody v C#
14/39
// Voláme funkci vypis vypis(pozdrav); return 0;}}
2. Výpis jednorozměrného pole celých čísel v C: void vypis(int cisla[],int n){ for(int i=0;i
v C#: class Program { static void vypis(int []cisla,int n){ for(int i=0;i
}}
3. Výpis dvourozměrného pole znaků v C: void vypis(char jmena[][20],int n){ for (int i=0;i
v C#: 2.11.11
Funkce v C a metody v C#
15/39
class Program { static void vypis(string[] jmena, int n) { for (int i = 0; i < n; i++) Console.WriteLine(jmena[i]); } static int Main() { string[] jmena={"Josef Novak","Petr Novotny","Marek Svoboda"}; int n = jmena.Length; vypis(jmena, n); return 0; }}
Funkční rozhraní
Funkční rozhraní je způsob komunikace mezi funkcí a volající jednotkou: Přes globální proměnné – nedoporučuje se, mohou vzniknout tzv. vedlejší ekty Přes parametry Pomocí návratové hodnoty
Volání funkce Uvedení jména funkce včetně jejich skutečných parametrů (argumentů) v kulatých závorkách. Volání funkce s návratovou hodnotu Na pravé straně příkazu přiřazení S=obsah(10,20); Jako parametr funkce printf: printf("%f", obsah(10,20)); Formální a skutečné parametry Formální parametry jsou parametry, uvedené v kulatých závorkách v definici funkce Skutečné parametry jsou parametry, uvedené v kulatých závorkách při volání funkce. Počet argumentů, které lze funkci předat podle normy ANSI C Norma ANSI C předepisuje možnost předat funkci až 31 argumentů .
Rekurzivní funkce Rekurzivní funkce, je funkce, která volá sama sebe, a to buď: Přímo
2.11.11
Funkce v C a metody v C#
16/39
Nepřímo – přes jiné funkce Funkce pro výpočet faktoriálu
v C: int faktorial(int n){ if(n==0)return 1; else return n*faktorial(n-1); } int main(){ int n; printf("Zadej n: "); scanf("%d",&n); printf("%d",faktorial(n)); return 0; }
v C#: class Program { static int faktorial(int n) { if (n == 0) return 1; else return n * faktorial(n - 1); } static void Main() { Console.WriteLine(faktorial(5)); }}
Rekurzivní funkce pro výpočet největšího společného dělitele:
v C: vypnsd(int &x,int &y){ if(x==y)return 0; if(x>y)x-=y; if(y>x)y-=x; vypnsd(x,y); } int main(){ int x,y; printf("Zadej 2 cisla: "); scanf("%d %d",&x,&y); vypnsd(x,y); printf("%d\n",x); return 0; }
v C#: class Program
2.11.11
Funkce v C a metody v C#
17/39
{ static int vypnsd(ref int x,ref int y){ if(x==y)return 0; if(x>y)x-=y; if(y>x)y-=x; vypnsd(ref x,ref y); return 1; } static void Main() { int nsd,a=52,b=650; vypnsd(ref a, ref b); Console.WriteLine(a); }}
Zajištění ukončení rekurze Funkce musí obsahovat podmínku, při jejímž splnění dojde k návratu z funkce, při kterém už nedochází k rekurzivnímu volání. if(n==0)return 1; else return n*fak(n-1);
Ve funkci vypnsd je to zajištěno příkazem: if(x==y)return 0;
Přetížené funkce Přetížená funkce je taková funkce, která má pod jedním názvem skryto více definic. Přetížené funkce jsou stejnojmenné funkce, lišící se počtem, nebo typem parametrů. Příklad (pouze deklarace): // Absolutní hodnota dlouhého celého čísla long lAbs(long x); // Asolutní hodnota reálného čísla double fAbs(double x); // Absolutní hodnota matice (Matice bude typ struktura) Matice mAbs(Matice x); // Absolutní hodnota komplexního čísla (Komplex je struktura) double cAbs(Komplex x);
Takto bychom museli postupovat v jazyku C, ale v C++ a C# máme díky možnosti přetěžování funkcí jinou možnost. Nevýhodou předchozího řešení je, že si uživatel musí pamatovat velké množství funkcí. Sice jsme se pokusili názvy zvolit dostatečně jasně, ale jak uvidíme později, lze to i jednodušeji, třeba takto (opět jenom deklarace): // Absolutní hodnota dlouhého celého číslo long Abs(long x); // Asolutní hodnota reálného čísla double Abs(double x); // Absolutní hodnota matice (Matice bude typ struktura) Matice Abs(Matice x); // Absolutní hodnota komplexního čísla (Komplex je struktura)
2.11.11
Funkce v C a metody v C#
18/39
double Abs(Komplex x);
Máme zde pouze jeden název funkce: Abs, ale jsou zde čtyři různé definice funkce (které jsme si zde neuvedli - definice funkce = tělo funkce). Definice funkcí se zřejmě budou lišit, protože algoritmus výpočtu absolutní hodnoty komplexního čísla je naprosto odlišný od výpočtu absolutní hodnoty celého čísla. Překladač sám pozná při překladu volání funkce, kterou z přetížených verzí máme na mysli. Rozlišovacím znamením jsou počet nebo typy parametrů. Z toho plyne i omezení při přetěžování funkcí (nebo metod), kdy je nutné, aby se jednotlivé přetížené funkce lišily počtem parametrů nebo jejich typem. Řešení an pomocí přetížené funkce mocnina: Máme definované dvě stejnojmenné funkce mocnina: se dvěma parametry s jedním parametrem
v C++: int mocnina(int a, int n) { int moc = 1; // Postupne násobíme základ... for (;n > 0;n--) moc *= a; return moc; } int mocnina(int a){ return a*a; } int main(){ int a; // pet na druhou - pouzije se funkce s jedním parametrem a = mocnina(5); printf("%d\n",a); // pet na druhou - pouzije se funkce se dvema parametry a = mocnina(5, 2); printf("%d\n",a); // pet na tretí a = mocnina(5, 3); printf("%d\n",a); return 0; }
v C#: class Program { static int mocnina(int a, int n) { int moc = 1;
2.11.11
Funkce v C a metody v C#
19/39
// Postupne násobíme základ... for (;n > 0;n--) moc *= a; return moc; } static int mocnina(int a) { return a * a; } static void Main() { int a; // pet na druhou - pouzije se metody s jedním parametrem a = mocnina(5); Console.WriteLine("{0}", a); // pet na druhou - pouzije se metody se dvema parametry a = mocnina(5, 2); Console.WriteLine("{0}", a); // pet na tretí a = mocnina(5, 3); Console.WriteLine("{0}", a); }}
Řešené úlohy 1. Funkce bez parametrů a bez návratové hodnoty – výpis textu void Pozdrav1(){ printf("Dobry den\n"); } void Pozdrav2(){ printf("Nazdar\n "); } int main(){ Pozdrav1(); Pozdrav2(); return 0; }
2. Funkce bez parametrů a bez návratové hodnoty – součet dvou čísel void sum(){ float a,b; scanf("%f %f",&a,&b); printf("%f", a+b); } int main(){ float c; sum(); return 0; }
2.11.11
Funkce v C a metody v C#
20/39
3. Příklad funkce bez parametrů s návratovou hodnotou – funkce vrací součet načtených čísel int float sum(){ float a,b; scanf("%f %f",&a,&b); return a+b; } int main(){ float c; c=sum(); printf("%f",c); return 0; }
Když se ve funkci dojde na příkaz return, funkce ihned končí. Return lze použít i samostatně bez vracené hodnoty: return; Ve funkci může být více příkazů return. 4. Funkce s parametry – výpis součtu parametrů typu float Argument funkce je hodnota, která se předává funkci při jejím volání. Norma ANSI C určuje, že funkci musí být možné předat 31 argumentů. Argumenty se předávají do speciálních proměnných – tzv. formálních parametrů funkce. Parametry se deklarují v závorkách za jménem funkce. U každého formálního parametru se musí uvést jeho datový typ. void sum(float x, float y); int main(){ sum(10,20); sum(1,1); sum(12.5,13.6); } void sum(float x, float y){ printf("%f",x+y); }
Funkce, které přebírají parametry se nazývají parametrizované funkce. Musíte zadat typ a jméno každého parametru a má-li funkce více parametrů, musíte je oddělit čárkami. Počet a typ argumentů (skutečných parametrů, s nimiž je funkce volaná) musí být stejný jako počet a typ formálních parametrů (s nimiž je funkce definovaná). 5. Funkce vypíše součet svých parametrů typu int Vytvořte funkci, která bude mít 2 parametry typu int. Přes tyto parametry přenesete do funkce 2 čísla a funkce vypíše jejich součet. Má-li funkce více parametrů, musíme je všechny v hlavičce funkce deklarovat.
2.11.11
Funkce v C a metody v C#
21/39
v C: void fce(int a,int b){ printf("%d\n",a+b); } int main(){ int a=30,b=40; fce(a,b); fce(1,2); return 0; }
v C#: class Program { static void Fce( int a, int b) { Console.WriteLine("Soucet je: {0}",a+b); } static void Main() { int a=30,b=50; Fce( a,b); Fce(1,2); } }
6. Funkce vrátí druhou mocninu svého parametru:
v C: int fce(int a){ return a*a; } int main(){ int a=3; printf("%d\n",fce(a)); return 0; }
v C#: class Program { static int Fce( int a) { return a*a; } static void Main() { int a=30; Console.WriteLine(Fce(a)); Console.WriteLine(Fce(2)); }
2.11.11
Funkce v C a metody v C#
22/39
}
7. Výpis tabulky druhých mocnin čísel od 2 do 100
v C: int fce(int a){ return a*a; } int main(){ int a; for(a=2;a<11;a++) printf("%d\t%d\n",a,fce(a)); return 0; }
v C#: class Program { static int Fce( int a) { return a*a; } static void Main() { int a; for (a = 2; a < 11; a++) Console.WriteLine(Fce(a)); } }
8. Výpis tabulky druhých a třetích mocnin čísel od 2 do 100
v C: int fce2(int a){ return a*a; } int fce3(int a){ return a*a*a; } int main(){ int a; for(a=2;a<11;a++) printf("%d\t%d\t%d\n",a,fce2(a),fce3(a)); return 0; }
v C#: class Program { static int Fce2( int a)
2.11.11
Funkce v C a metody v C#
23/39
{ return a*a; } static int Fce3(int a) { return a * a*a; } static void Main() { int a; for (a = 2; a < 11; a++) Console.WriteLine("{0}\t{1}",Fce2(a),Fce3(a)); } }
9. Použití jedné funkce pro výpočet druhých a třetích mocnin Totéž lze vyřešit pomocí jedné funkce mocnina, která je obecná – má 2 parametry: umocňované číslo a a exponent n
v C: int mocnina(int a,int n){ int moc=a,i; for(i=1;i
v C#: class Program { static int mocnina( int a,int n) { int moc = a, i; for (i = 1; i < n; i++) moc = moc * a; return moc; } static void Main() { int a; for (a = 2; a < 11; a++) Console.WriteLine("{0}\t{1}",mocnina(a,2),mocnina(a,3)); } }
Funkci mocnina voláme v Console.WriteLine dvakrát: poprvé se skutečnými parametry a,2 – umocní a na druhou
2.11.11
Funkce v C a metody v C#
24/39
podruhé se skutečnými parametry a,3 – umocní a na třetí
10. Stáří Nováků Vytvořte program, který bude mít v mainu/Mainu definované pole Novak, které bude obsahovat roky narození 3 Nováků. Nechť po zadání aktuálního roku (v mainu/Mainu) program vypíše, kolik je jim let. Výpis realizujte funkcí vypis, která bude mít dva parametey: pole Novak a aktuální rok. Zadej aktualni Stari Novaku: 1. Novak ma 80 2. Novak ma 50 3. Novak ma 20
rok: 2010 let let let
void vypis(int Novak[],int rok){ int i; printf("Stari Novaku:\n"); for(i=0;i<3;i++) printf("%d. Novak ma %d let\n",i+1,rok-Novak[i]); } int main(){ int Novak[]={1930,1960,1990}; int rok; printf("Zadej aktualni rok: "); scanf("%d",&rok); vypis(Novak,rok); return 0; }
11. Vytvořte program, který vypíše tabulku arabských a odpovídajících římských číslic.
v C: void vypis(char rim[],int arab[]){ int i; printf(" Index\tARAB\tRIM\n"); for (i=0;i<7;i++) printf(" %d\t%d\t%c\n",i,arab[i],rim[i]); } int main(){ char rim[]={'I','V','X','L','C','D','M'}; int arab[]={1,5,10,50,100,500,1000}; vypis(rim,arab); return 0; }
2.11.11
Funkce v C a metody v C#
25/39
12. Vytvořte program, který pro zadanou arabskou číslici vypíše její římský ekvivalent. Zadání řešte pomocí funkce vypis, která bude mít 3 parametry: pole římských čísel, pole arabských čísel a zadané arabské číslo. void vypis(char rim[],int arab[],int a){ int i; for (i=0;i<7;i++)if (a==arab[i]) break; if(i>6)printf("\nZadane cislo neni v tabulce\n"); else printf(" %c\n",rim[i]); } int main(){ char rim[]={'I','V','X','L','C','D','M'}; int arab[]={1,5,10,50,100,500,1000}; int i; int a; printf("Zadej arabske cislo:"); scanf("%d",&a); vypis(rim,arab,a); return 0; }
Úprava funkce vypis tak, že funkce nalezené římské číslo nevypíše, ale vrátí jako návratovou hodnotu. Tomu musí odpovídat volání funkce v mainu jako parametr funkce printf. char vypis(char rim[],int arab[],int a){ int i; for (i=0;i<7;i++)if (a==arab[i]) break; if(i>6)printf("\nZadane cislo neni v tabulce\n"); else return rim[i]; } int main(){ char rim[]={'I','V','X','L','C','D','M'}; int arab[]={1,5,10,50,100,500,1000}; int i,a; printf("Zadej arabske cislo:"); scanf("%d",&a); printf("Rimska cislice je: %c", vypis(rim,arab,a)); return 0; }
13. Vytvořte program, který pro zadanou římskou číslici vypíše její arabský ekvivalent. Zadání řešte pomocí funkce vypis, která bude mít 3 parametry: pole římských čísel, pole arabských čísel a zadané arabské číslo. int vypis(char rim[],int arab[],char a){ int i; for (i=0;i<7;i++)if (a==rim[i]) break; if(i>6)printf("\nZadane cislo neni v tabulce\n"); else return arab[i]; }
2.11.11
Funkce v C a metody v C#
26/39
int main(){ char rim[]={'I','V','X','L','C','D','M'}; int arab[]={1,5,10,50,100,500,1000}; int i; char a; printf("Zadej rimske cislo:"); scanf("%c",&a); printf("%d", vypis(rim,arab,a)); return 0;}
14. Nalezení maxima, minima a průměru čísel v poli. V mainu definujte a inicializujte pole racionálních čísel a napište funkce, který stanoví maximální, minimální a průměrnou hodnotu čísel v poli a vypíše je! int maximum(int cisla[],int a){ int max,i; max=cisla[0]; for(i=1;i
max)max=cisla[i]; return max; } int minimum(int cisla[],int a){ int min,i; min=cisla[0]; for(i=1;i
15. Kódovací a dekódovací program Napište program, který představuje jednoduché kódovací zařízení. Převádí napsané znaky z pole znaků do kódovaného tvaru tak, že ke každému písmenu přičte 1. To znamená, že z ´A´ se stane ´B´ atd. Zakódovaný řetězec vypište. Dále vytvořte funkci, která zakódovaný řetězec dekóduje do původního tvaru. #include <stdio.h> #include <string.h> void koduj(char text[]){
2.11.11
Funkce v C a metody v C#
27/39
int i; for(i=0;i<strlen(text);i++) text[i]=text[i]+1; puts(text); } void dekoduj(char text[]){ int i; for(i=0;i<strlen(text);i++) text[i]=text[i]-1; puts(text); } int main(){ char text[80]; printf("Zadej retezec:"); gets(text); koduj(text); printf("Dekodovany retezec:"); dekoduj(text); return 0; }
16. Zápis průměru odpovídajících si prvků dvou polí do třetího pole Definujte a inicializujte 2 celočíselná pole, do kterých zadáte známky dvou studentů z 10 předmětů. Deklarujte 1 pole racionálních čísel, do kterého zapíšete průměry známek z jednotlivých předmětů! Pro řešení zadané úlohy vytvořte funkce prumer a vypis. void prumer(int cis1[],int cis2[],float prum[]){ int i; for(i=0;i<10;i++) // cyklus pro výpočet prum[i]=(cis1[i]+cis2[i])/2.; } void vypis(float prum[]){ int i; printf("Prumer je:\n"); for(i=0;i<10;i++) // cyklus pro výpis printf("%.2f ",prum[i]); } int main(){ int cis1[]={1,5,2,3,1,4,2,3,3,4}; int cis2[]={2,4,3,2,3,3,1,2,4,3}; float prum[10]; int i; prumer(cis1,cis2,prum); vypis(prum); return 0; }
17. Funkce pro čtení a výpis pole celých čísel Vytvořte funkce pro čtení a výpis hodnot celočíselného pole, lokálně deklarovaného v mainu. 2.11.11
Funkce v C a metody v C#
28/39
V mainu je zavolejte v pořadí: cteni, vypis. Funkce vypis nechť vypíše čísla v poli osmičkově, desítkově a šestnáctkově. void cteni(int cis[]){ int i; for(i=0;i<5;i++) scanf("%d",&cis[i]); } void vypis(int cis[]){ int i; for(i=0;i<5;i++) printf("%o %d %x\n",cis[i],cis[i],cis[i]); } int main(){ int cis[5]; cteni(cis); vypis(cis); return 0; }
18. Předávání parametrů odkazem – změna hodnot parametrů ve funkci Vytvořte funkci se dvěma parametry typu int, předávanými odkazem. Funkce změní hodnoty těchto parametrů. main převezme z funkce změněné hodnoty parametrů a vypíše jejich součet:
v C++: void fce(int &a,int &b){ a=20; b=30; } int main(){ int a,b; fce(a,b); printf("Prenos hodnot pres parametry: %d\n",a+b); return 0; } v C#: class Program { static void fce(ref int a, ref int b) { a = 20; b = 30; } static void Main() { int a=0, b=0; fce(ref a, ref b); Console.WriteLine("{0}", a + b); } }
2.11.11
Funkce v C a metody v C#
29/39
19. Výměna obsahu parametrů Vytvořte funkci, která vymění obsah dvou parametrů typu int.
v C: Aby došlo ke změně, nutno předat parametry odkazem: void zmena(int &x, int &y){ int temp = x; x = y; y = temp; } // Použití – nyní už dojde ke změně obsahu a,b int main(){ int a = 10; int b = 5; zmena(a,b); // volání je stejné jako hodnotou printf("%d %d\n ",a,b); return 0; }
Chcete-li, aby funkce změnila obsah argumentů (skutečných parametrů), použijte předávání parametrů odkazem – bylo zavedeno až v C++.
v C#: class Program { static void zmena(ref int x, ref int y) { int temp = x; x = y; y = temp; } static void Main() { int a=10, b=5; zmena(ref a, ref b); Console.WriteLine("{0} {1}", a , b); } }
20. Výpočet obsahu a obvodu obdélníka Vytvořte funkci obsah_a_obvod(float a,float b,float &s,float &o), která počítá obsah a obvod obdélníka, jehož strany jsou do funkce přenášeny jako první dva parametry. Vypočítané hodnoty funkce vrací do volající jednotky přes 3. a 4. parametr, předávané odkazem s a o.
v C++:
2.11.11
Funkce v C a metody v C#
30/39
Volání odkazem je v C++ vyjádřeno znakem & před parametrem. void obsah_a_obvod(float a,float b,float &s,float &o){ s=a*b; o=2*(a+b); } int main(){ float a,b,s,o; scanf("%f %f",&a,&b); obsah_a_obvod( a, b, s, o); printf("Plocha: %f\n",s); printf("Obvod: %f\n",o); return 0; }
Není-li před formálním parametrem & , je tento pro funkci pouze vstupní Je-li před formálním parametrem & , je tento pro funkci vstupní i výstupní Vstupním parametrem mohou hodnoty do funkce vstupovat Výstupním parametrem mohou hodnoty z funkce vystupovat
v C#: class Program { static void obsah_a_obvod(double a, double b,out double s,out double o) { s=a*b; o=2*(a+b); } static void Main(){ double a, b, s, o; a=Convert.ToDouble(Console.ReadLine()); b = Convert.ToDouble(Console.ReadLine()); obsah_a_obvod(a, b, out s,out o); Console.WriteLine("Plocha: {0}\n", s); Console.WriteLine("Obvod: {0}\n", o); }}
Není-li před formálním parametrem out, nebo ref , je tento pro metodu pouze vstupní Je-li před formálním parametrem out, nebo ref , je tento pro metodu vstupní i výstupní Vstupním parametrem mohou hodnoty do metody vstupovat Výstupním parametrem mohou hodnoty z metody vystupovat Nahradíme-li out ref, vypíše překladač chybu. Aby se odstranila, je třeba proměnné s a o inicializovat – např. vynulovat: class Program { static void obsah_a_obvod(double a, double b, ref double s, ref double o) { s = a * b; o = 2 * (a + b);
2.11.11
Funkce v C a metody v C#
31/39
} static void Main() { double a, b, s=0, o=0; a = Convert.ToDouble(Console.ReadLine()); b = Convert.ToDouble(Console.ReadLine()); obsah_a_obvod(a, b, ref s, ref o); Console.WriteLine("Plocha: {0}", s); Console.WriteLine("Obvod: {0}\n", o); } }
21. Výpočet aritmetických operací
v C++: Funkce vypocty realizuje všechny možné aritmetické operace s s prvními dvěma parametry, které jsou předávány hodnotou. Výsledky výpočtů jsou předávány pomocí dalších čtyř parametrů odkazem. void vypocty(float a,float b,float &s,float &r,float &k,float &p){ s=a+b; r=a-b; k=a*b; p=a/b; } int main(){ float a,b,s,r,k,p; scanf("%f %f",&a,&b); vypocty( a, b, s, r,k,p); printf("Soucet: %f\n",s); printf("Rozdil: %f\n",r); printf("Soucin: %f\n",k); printf("Podil: %f\n",p); return 0; }
v C#: class Program { static void vypocty(double a, double b, out double s, out double r, out double k, out double p) { s=a+b; r = a - b; k = a * b; p = a / b; } static void Main(){ double a, b, s, r, k, p; a=Convert.ToDouble(Console.ReadLine()); b = Convert.ToDouble(Console.ReadLine()); vypocty(a, b, out s, out r, out k, out p); Console.WriteLine("Součet: {0}\n", s);
2.11.11
Funkce v C a metody v C#
32/39
Console.WriteLine("Rozdíl: {0}\n", r); Console.WriteLine("Součin: {0}\n", k); Console.WriteLine("Podíl: {0}\n", p); }}
22. Přepis programu – odstranění globálních proměnných Přepište následující program tak, aby nepoužíval globální proměnné, ale hodnoty, načtené ve funkci přenášel přes parametry. Program ve funkci cteni načte do globálních proměnných a,b 2 racionální čísla a v mainu se vypíše jejich součet. V mainu je čtení čísel a výpis jejich součtu zacykleno cyklem do- while, který trvá do zadání nulové hodnoty prvního čísla. Ve funkci je to vyřešeno příkazem return 1 je-li zadaná nulová hodnota a.
v C++: float a,b; int cteni(){ scanf("%f",&a); if(!a)return 1; scanf("%f",&b); return 0; } int main(){ do{ if(cteni())break; printf("%f\n",a+b); }while(1); return 0; }
Chceme-li zrušit globální proměnné, musíme načtené hodnoty a,b vracet do mainu přes parametry předávané odkazem, co se projeví tím, že před a i b v definici funkce uvedeme &. int cteni(float &a,float &b){ scanf("%f",&a); if(!a)return 1; scanf("%f",&b); return 0; } int main(){ float a,b; do{ if(cteni(a,b))break; printf("%f\n",a+b); }while(1); return 0; }
v C#: 2.11.11
Funkce v C a metody v C#
33/39
class Program { static double a, b; // Globální proměnné static bool cteni() { a = Convert.ToDouble(Console.ReadLine()); if (a == 0) return true; b = Convert.ToDouble(Console.ReadLine()); return false; } static void Main() { while (!cteni()) Console.WriteLine("{0}\n", a + b); } }
Chceme-li zrušit statické globální proměnné, musíme načtené hodnoty a,b vracet do Mainu přes parametry předávané odkazem, co se projeví tím, že před a i b v definici metody uvedeme out. using System; class Program { static bool cteni(out double a, out double b) { a = Convert.ToDouble(Console.ReadLine()); if (a == 0) { b = 0; return true; } b = Convert.ToDouble(Console.ReadLine()); return false; } static void Main() { double a, b; while (!cteni(out a, out b)) Console.WriteLine("{0}\n", a + b); } }
23. Výpis jmen a průměrů Vytvořte program, který bude obsahovat funkci vypis, která bude mít 3 parametry: Pole, obsahující jména žáků Pole, obsahující průměry žáků Počet prvků polí Funkce vypíše jména žáků a jejich průměry, které jsou na odpovídající pozici v poli.
v C: void vypis(char jmena[][8],float prum[],int n){ for(int i=0;i
2.11.11
Funkce v C a metody v C#
34/39
float prum[]={1.7,2.8,3.1,2.2,1.4,3.05,2.9,1.95}; char jmena[][8]={"Petr","Pavel","Josef","Martin","Jan","Adam", "Zdenek","Karel","David"}; int n=sizeof(jmena)/20; vypis(jmena,prum,n); getch(); return 0; }
v C#: class Program { static void vypis(string []jmena,float []prum,int n){ for(int i=0;i
24. Výpis hlavních měst různých států
v C: void vypis(char staty[][10],char mesta[][10],int n){ for(int i=0;i
v C#: class Program { static void vypis(string []staty,string []mesta, int n) { for(int i=0;i
2.11.11
Funkce v C a metody v C#
35/39
string []staty = { "Cesko", "Francie", "Polsko", "Anglie" }; int n=staty.Length; vypis(staty,mesta,n); return 0; }}
25. Třídění čísel v poli Na obrázku je znázorněna metoda bublinkového třídění. Jednotlivá čísla se porovnávají se všemi čísly napravo. Pokud se najde menší číslo, dojde k jejich prohození. V důsledku tohoto postupu se nejmenší čísla dostanou na pozici nejvíc vlevo. Vytvořte program, který bude pomocí funkce trideni třídit pole celých čísel bublinkovou metodou. Funkce trideni bude mít 2 parametry: Tříděné celočíselné pole Počet prvků v poli
v C: void trideni(int a[],int n){ int i,j,pom; for(i=0;ia[j]){ pom=a[j]; a[j]=a[i]; a[i]=pom; }}} int main(){ int i,a[]={3,2,5,7,2,8}; int n=sizeof(a)/sizeof(int); trideni(a,n); for(i=0;i
v C#: class Program { static void trideni(int []a,int n){ int i,j,pom; for(i=0;ia[j]){ pom=a[j]; a[j]=a[i]; a[i]=pom; }}} static int Main(){ int []a={3,2,5,7,2,8};
2.11.11
Funkce v C a metody v C#
36/39
int i,n=a.Length; trideni(a,n); for(i=0;i
26. Generátor náhodných čísel – simulace hodu kostkou Vytvořte program,který simuluje hod kostkou s využitím funkce generuj, která obsahuje cyklus, v němž se opakovaně generuje náhodné číslo od 1 do 6, dokud nestiskneme libovolnou klávesu.
v C: #include #include<stdlib.h> #include<stdio.h> #include #include<windows.h> void generuj(){ do{ printf("%d ",rand()%5+1); Sleep(100); }while(!kbhit()); printf("\n\n\n"); } int main(){ srand(time(NULL)); generuj(); getch(); return 0; }
v C#: using System; using System.Threading; class Program { static void generuj(){ Random rand = new Random(); do{ Console.Write("{0} ",rand.Next(5)+1); Thread.Sleep(100); }while(!Console.KeyAvailable); } static int Main(){ generuj(); return 0; }
2.11.11
Funkce v C a metody v C#
37/39
} 27. Zápis generovaných čísel do pole S využitím funkcí napište program, který simuluje hod mincí. Využijte generátor náhodných čísel. Hody mincí se opakují, dokud nestisknete libovolnou klávesu (funkce kbhit()). Výsledky zapisujte do pole, které na závěr vypište. Vytvořte funkce generuj a vypis. #include #include<stdlib.h> #include<stdio.h> #include #include<windows.h> int pole[1000]; int pocet=0; void generuj(){ int i=0; do{ pole[i]=rand()%2; // generuje č. do 2 printf("%d\b",pole[i]); i++; pocet++; Sleep(100); }while(!kbhit()); printf("\n\n\n"); } void vypis(){ for(int i=0;i<pocet;i++) printf("%d ",pole[i]); } int main(){ srand(time(NULL)); // inicializace generátoru náh. čísel printf("********************************\n"); printf("Hod minci....."); generuj(); vypis(); getch();getch(); return 0; }
v C#: using System; using System.Threading; class Program { static void generuj(ref int []pole,ref int pocet){ Random rand = new Random(); int i=0;
2.11.11
Funkce v C a metody v C#
38/39
do{ pole[i] = rand.Next(2); // generuje č. do 2 i++; Thread.Sleep(500); }while(!Console.KeyAvailable); pocet=i; } static void vypis(int []pole,int pocet){ for(int i=0;i<pocet;i++) Console.Write("{0} ",pole[i]); } static int Main(){ int []pole=new int[100]; int pocet = 0; Console.WriteLine("********************************\n"); Console.Write("Hod minci....."); generuj(ref pole,ref pocet); vypis(pole,pocet); return 0; } }
Shrnutí: V kapitole je rozebráno použití funkcí/metod v jazycích C a C#. Jsou ukázány možnosti komunikace funkcí/metod s jinými funkcemi/metodami pomocí návratové hodnoty, parametrů a globálních proměnných. Uvedené přístupy jsou vysvětleny na řadě příkladů. Jsou uvedeny i příklady rekurzivních a přetížených funkcí/metod.
2.11.11
Funkce v C a metody v C#
39/39