Parametr funkce
Parametr funkce je označení pro vstupní data funkce v programování.
Formální a skutečný parametr
Tento pojem ve skutečnosti zahrnuje dvě odlišné věci:
- Formální parametr je parametr použitý při psaní funkce, její vnitřní proměnná. Ta je vždy před zpracováním nahrazována hodnotou skutečného parametru.
- Skutečný parametr je proměnná nebo výraz dosazený při volání funkce. Při volání funkce je jeho hodnota přiřazena formálnímu parametru.
Způsoby předávání parametru
Navázání skutečného parametru na formální lze dosáhnout několika odlišnými způsoby. Ve většině dnešních programovacích jazyků se používají hlavně předávání parametrů hodnotou a odkazem:
- Při předávání hodnotou (call-by-value) se těsně před zpracováním těla funkce skutečný parametr vyčíslí a výsledek se zkopíruje do lokální proměnné uvnitř volané funkce. Jakékoli změny parametru uvnitř volané funkce nemají vliv na volající funkci, neboť se pracuje s lokální kopií, předávání hodnotou tedy lze používat pouze pro vstupní parametry. Tento způsob je typický např. při vytváření aritmetických funkcí.
- Při předávání odkazem (call-by-reference) se formální parametr uvnitř volané funkce bere jen jako jiné označení (alias) pro proměnnou předanou jako skutečný parametr, tzn. ve volané funkci se pracuje přímo s předávanou proměnnou, nevytváří se tedy kopie (což zvláště u strukturovaných proměnných znamená zpravidla úsporu času i paměti). Volaná funkce změnou parametru ovlivňuje i volající funkci (takže předávání odkazem lze používat pro výstupní či vstupně-výstupní parametry), nevýhodou však je, že parametrem může být jen proměnná a nikoli výsledek obecného výrazu. Předávání odkazem se obvykle implementuje pomocí ukazatele na předávanou proměnnou.
Někdy se používají také o něco netradičnější způsoby předávání jako např. předání hodnotou s kopií při návratu (call-by-copy-restore) nebo předání jménem (call-by-name).
Příklady
Předávání jménem
Předávání jménem se příhodně používá ve funkcionálních jazycích, v makrojazycích a skriptovacích jazycích využívajících textové nahrazování (Tcl). Z procedurálních kompilovaných jazyků bylo použito např. v Algolu 60, ale v těchto jazycích jde o anachronismus způsobený špatnou představou tvůrců jazyka o fungování překladačů. Výsledný efekt se podobá předávání referencí, ovšem hodnota parametru se v těle funkce vyhodnocuje při každém použití.
Příklad:
procedure P(X); integer X; begin write(X); I:=I+1; write(X); end
Při zavolání funkce:
P(A[i]);
se pak vypíší prvky v poli A na místě I a I+1.
Příklad v jazyce C
Předávání hodnotou
void Zamen(int a, int b) //zameni hodnoty v promennych
{
int pom;
pom = a;
a = b;
b = pom;
}
Tuto metodu budeme volat v programu následovně:
int main(void)
{
int promennaA = 10, promennaB = 20;
Zamen(promennaA, promennaB);
return 0;
}
Po tomto zavolání metody Zamen budou hodnoty v proměnných promennaA 10 a v proměnné promennaB bude hodnota 20. Tedy k žádné změně nedojde. Je to tím, že pokud předáváme parametry funkci hodnotou, tak pracujeme vlastně s kopiemi proměnných a tím je průběh funkce izolovaný.
Pokud chceme, aby volání funkce ovlivnilo parametry, které předáváme, musíme předávat parametry funkci ukazatelem (referencí) na danou proměnnou.
Předávání ukazatelem
void Zamen(int* a, int* b) //zameni hodnoty v promennych
{
int pom = *a;
*a = *b;
*b = pom;
}
Tuto metodu budeme volat v programu následovně:
int main(void)
{
int promennaA = 10, promennaB = 20;
Zamen(&promennaA, &promennaB);
return 0;
}
Po zavolání funkce tímto způsobem se již odkazuje na místo v paměti, kde jsou uložené proměnné promennaA a promennaB a tím dosáhneme toho, že po zpracování funkce bude v proměnné promennaA hodnota 20 a v proměnné promennaB bude 10.
Příklad v jazyce C#
Předávání parametrů v jazyce C# je velice podobné jazyku C, jen zde dochází k malé změně definice a volání takové funkce.
Předávání hodnotou
void Zamen(int a, int b)
{
int pom = a;
a = b;
b = pom;
}
Tuto metodu budeme volat v programu následovně:
static void Main(string[] args)
{
int promennaA = 10;
int promennaB = 20;
Zamen(promennaA, promennaB);
}
Jak můžeme vidět, tak předávání parametrů funkci hodnotou v jazyce C# je totožné s jazykem C a dočkáme se i stejného výsledku, tj. promennaA a promennaB budou po zavolání funkce beze změny.
Předávání odkazem
void Zamen(ref int a, ref int b) // zameni hodnoty v promennych
{
int pom = a;
a = b;
b = pom;
}
Tuto metodu budeme volat v programu následovně:
static void Main(string[] args)
{
int promennaA = 10;
int promennaB = 20;
Zamen(ref promennaA, ref promennaB);
}
Po předání parametrů funkci tímto způsobem dosahujeme stejného výsledku jako v jazyce C a ve výsledku máme tedy po zavolání funkce v našich proměnných promennaA a promennaB hodnotu 20 resp. 10.
Jazyk C# umí navíc další možnosti jak předávat parametry funkci. Je zde možnost proměnného počtu parametrů funkce a také možnost použití modifikátoru out, který je blízký modifikátoru ref. Na následujících příkladech si ukážeme funkčnost těchto možností.
Proměnný počet parametrů
int Suma(params int[] cisla) // secte vsechna cisla zadana jako parametry
{
int suma = 0;
for (int i = 0; i < cisla.Length; i++)
{
suma += cisla[i];
}
return suma;
}
Tuto metodu budeme volat v programu následovně:
static void Main(string[] args)
{
int suma = Suma(1, 2, 3, 4, 5); // libovolny pocet parametru typu int
}
Předání odkazem (modifikátor out)
Tato možnost předání parametru funkci je podobná jako u předávání odkazem (ref). Tento zápis používáme, pokud potřebujeme z funkce například více výstupů. Například potřebujeme zjistit, jestli se výpočet funkce provedl v pořádku, a tak funkce vrací hodnotu bool a výsledek je tedy potřeba získat přes modifikátor out. Bylo by možné použít i možnost ref, ale při použití modifikátoru out je nucen programátor parametr funkce s tímto modifikátorem ve funkci naplnit. Alternativním řešením by bylo použití typu int?, který podporuje navíc i hodnotu null, která by značila neúspěch.
// secte hodnoty a, b a ulozi do prommene, ktera je jako parametr soucet, a vraci typ bool, zdali se soucet povedl
bool Soucet(int a, int b, out int soucet)
{
try
{
soucet = a + b; // pokud je nejaky parametr out, je nutne ho v tele funkce pouzit (narozdil od ref)
return true;
}
catch (Exception)
{
soucet = 0;
return false; // soucet se nepovedl
}
}
Tuto metodu budeme volat v programu následovně:
static void Main(string[] args)
{
int a = 10;
int b = 20;
int soucet;
bool vypocetOK = Soucet(a, b, out soucet);
}