Funkce
Na předchozích seminářích jsme se dozvěděli jak pomocí větvení programu ovlivnit chování programu na základě vstupu, nebo pomocí cyklů opakovat n-krát stejný příkaz bez toho bychom jej museli psát n-krát pod sebou. Nabízí se tedy otázka. Je možné opakovat určitou část kódu na různých místech v programu? Ano a to pomocí funkcí. Každý program v C obsahuje alespoň jednu fuknci a to konkrétně funkci main
.
Výhody funkcí
- Vyvarujeme se opakování kódu a tím způsobené chyby (copy-paste).
- Redukujeme čas potřebný pro přeložení (kompilaci) programu.
- Zjednodušují znovupoužítí kódu.
Definice funkce
Definice nové funkce se provádí mimo funkci main
. Skládá se z návratového typu tedy jakého typu je hodnota kterou funkce vrací. Pokud nechceme, aby funkce vracela hodnotu tak návratový typ uvedeme void
. Hodnotu vracíme pomocí return
. Pokud má funkce návratový typ jiný než void
, tak funkce musí vracet hodnotu. Dále funkce má jméno pomocí kterého funkci voláme a jako poslední následuje seznam parametrů funkce, kde každý parametr má svoje jméno a datový typ.
type function_name(type1 p1, type2 p2, ..., typen pn) {
// Function body
return value;
}
Volání funkce
Mějme funkci expt
která vypočítá n-tou mocninu daněho základu. Pokud cheme tuto funkci zavolat, tak použijeme její název a do závorek dáme argumenty. V kódu níže voláme fuknci expt
následovně expt(base, exponent)
, kde base
a exponent
jsou argumenty.
#include <stdio.h>
double expt(double base, int exponent) {
double result = 1.0;
for (int i = 0; i < exponent; i += 1) {
result *= base;
}
return result;
}
int main() {
double base;
int exponent;
printf("Zadejte základ a expoenent: \n");
scanf("%lf %i", &base, &exponent);
printf("%.1lf na %i je rovno %.1lf", base, exponent, expt(base, exponent));
return 0;
}
Rozsah platnosti proměnných
Platnost proměnné určuje kus kódu, kde tato proměnná existuje. Můžeme tedy přístupovat k její hodnotě případně přiradit jinou hodnotu apod. Platnost proměnné je v bloku kódu (kód mezi závorkami { }), kde byla definovaná. Hodnota proměnné se nejdříve hledá v bloku, kde ji chceme použít. Pokud není nalezena definice, tak hledáme o úroveň výše, tedy v bloku který obsahuje blok ve kterém cheme použít naši proměnnou a tak pokračujeme dokud nenajdeme definici proměnné a nebo neúspěšně hledáme v nejvyšším bloku, což je celý soubor a proměnná je definovaní mímo všechny funkce. Proměnná definovaná v bloku je nazýváná lokální proměnná a proměnnou definovanou v nejvyšším bloku navýváme globální.
#include <stdio.h>
//Globalni promenna
int square_size = 10;
// Funkce modifikuje globalni promennou
void resize_square() {
square_size = 20;
}
// Funkce vytiskne na obrazovku ctverec * a
// pouziva hodnotu globalni promenne square_size.
void print_square() {
for (int row = 0; row < square_size; row += 1) {
for (int col = 0; col < square_size; col += 1) {
printf("*");
}
printf("\n");
}
}
int area() {
// Lokalni promenna ktera zastini hodnotu globalni.
int square_size = 5
return square_size * square_size;
}
int main() {
print_square(); // Vytiskne ctverec o delce strany 10
printf("%i", area()); // Vytiskneme obsah ctverce
resize_square(); // Zmenime hodnotu globalni promenne
print_square(); // Vytiskne ctverec o delce strany 20
printf("%i", area()); // Vytiskneme obsah ctverce
// Jake hodnoty vrati prvni a druhe volani funkce area.
return 0;
}
V programech bychom měli používat globální proměnné co nejměně. Může pak dojít k špagety kódu, což je situace, kdy jsou jednotlivé části programu svázány globalními proměnnými. Takový kód je nesrozumitelný pro ostatní programátory ale časem i pro jeho autora. Funkce by měli být na sobě co nejméně závislé.
Předávání parametrů hodnotou
Máme funkci swap
která prohodí hodnoty v proměnných. Jaký bude výsledek?
void swap(int a, int b) {
int swap_help = a;
a = b;
b = swap_help;
}
int main() {
int a = 10;
int b = 20;
swap(a, b);
printf("a = %i, b = %i", a, b);
return 0;
}
Hodnoty se po zavolání funkce nezmění a to proto, že argumenty se předávají hodnotou. Hodnota proměnných se překopíruje na jiné místo v paměti a proměnné a
a b
používané v těle funkce jsou lokální proměnné funkce swap
. Jednu vyjímku ale máme a to pokud předáme pole jako argument. V tomto případě jsme schopni v těle funkce měnit hodnoty argumentu.
void erase_array(int array[], int size) {
for(int i = 0; i < size; i += 1) {
array[i] = 0;
}
}
int main() {
int foo[5] = {1,2,3,4,5};
erase_array(foo, 5);
// Zde jsou vsechny prvky pole rovny 0.
return 0;
}
Úkoly
Přepište úlohy z minulých kapitol za pomoci funkcí. To znamená: naprogramujte funkci, která dělá požadovanou věc, a poté ji zavolejte z funkce main. Musíte vhodně zvolit argumenty a návratovou hodnotu funkcí.
Napište program, který nalezne všechna čtyřciferná čísla, která jsou dělitelná číslem, které dostaneme jako sumu čísla tvořeného první a druhou číslicí a čísla tvořeného třetí a čtvrtou číslicí. Např. číslo 3417 je dělitelné číslem 34 + 17. Vhodné části algoritmu realizujte pomocí funkcí.
Napište program, který pro dané přirozené n spočítá sumu:
1! + (1 + 2)! + (1 + 2 + 3)! + ... + (1 + 2 + 3 + ... + n)!
(Testujte pouze pro malá n, výsledek může být obrovské číslo a může dojít k přetečení).