Függvény
A programozásban általában függvénynek nevezünk egy olyan programkód-részletet, ami valamilyen eredményt szolgáltat. A programnyelvek zömében a függvények nyelvi szinten is megjelennek. Általában a függvények eredménye egyetlen jól körülhatárolt érték, adat, vagy objektum, amit a függvény visszatérési értékének nevezünk. Sok példa van arra is, mikor a függvény ezen felül más hatást is kelt, egyéb adatokat is számol, objektumokat módosít, vagy kimenetet produkál. A visszatérési értéket a függvény általában nem önmagában, hanem valamilyen paramétereknek megfelelően állítja elő. A paraméterek is meg szoktak jelenni a forráskódban. Ennek gyakori jelölése az, hogy a függvény neve után egy zárójelben fel van sorolva a paraméterek neve és típusa.
A függvények többnyire saját (lokális) változókkal és típusokkal is rendelkezhetnek, vagyis önálló alprogramokként foghatók fel. Bizonyos nyelvekben azokat az alprogramokat is függvénynek hívják, amik nem generálnak visszatérési értéket. A kódban ezt általában egy void kulcsszóval jelzik.
Argumentumok[szerkesztés]
A függvény eredményének képzéséhez szükséges paramétereket argumentumoknak is hívjuk. Egy függvényhez általában néhány (1-5) argumentum tartozik, 0 is megengedett. A túl sok argumentum nehezen olvashatóvá teszi a kódot, ezért ilyen esetekben javasolt az argumentumok összevonása valamilyen objektumba, vagy rekordba. A szigorúan típusos nyelveknél a függvény deklarációjában meg kell adni az argumentumok típusait is. A deklarációban szereplő argumentumokat formális paramétereknek, a függvényhíváskor átadottakat aktuális paramétereknek hívjuk. A deklaráció egyfajta elő-ellenőrzésre használható, a fordító nem engedélyez olyan függvényhívást, amiben az aktuális paraméterek nem felelnek meg a deklarációban jelzetteknek.
Egy függvény argumentumai átadásuk módja szerint többfélék lehetnek:
- Érték szerinti átadásról beszélünk, ha a függvény csak az argumentum értékével dolgozhat. Általában a függvénytörzs módosíthatja az értéket, de ez nem lesz hatással a program többi részére. A fordítók többnyire a program vermében helyezik el ilyenkor az értéket. Nagy adatstruktúrák esetén ezért kerülendő, mert növeli a veremhasználatot és a másolás időt is igényel.
- Cím szerinti átadásról beszélünk, ha a függvény a paraméter futás közbeni memóriacímét kapja meg. Ilyenkor a hivatkozott adatot, vagy objektumot a címen keresztül éri el, vagyis az esetleges módosítások visszahathatnak a függvényen kívüli programrészre. Ebbe a kategóriába tartoznak általában a konstans (const), referencia (var), vagy kimeneti (out) paraméterek. Van, hogy a programnyelv a cím szerinti átadásnál elrejti a konkrét mutatót, az argumentumok ilyenkor a függvény változóiként kezelhetők.
Függvényhívás[szerkesztés]
Egy függvény futtatását függvényhívásnak nevezzük. Az aktuális paraméterek a függvény által elérhető helyre (többnyire a program vermébe) kerülnek, és a vezérlés átadódik a függvénynek. Az elvégzi a feladatát, kiszámolja a visszatérési értéket, elérhetővé teszi (a verembe az argumentumok helyett), majd visszaadja a vezérlést a hívó programrésznek. Az általa lefoglalt memória terület felszabadul.
A függvény meghívásakor a verembe lefoglalásra kerül a függvény visszatérési címe,a lokális deklarációjában létrehozott változók, a függvény fejlécében meghatározott paraméterlistában szereplő argumentumok (paraméterek) is. Ha a függvény elvégezte a szükséges számításokat, és elérte a függvény törzsének végét jelző záró részt (ez pascalban az End;
), a visszatérési cím alapján visszaadja a vezérlést a hívónak.
Egy függvény futás közben önmagát is hívhatja, amit rekurziónak nevezünk. Más függvényeket is felhasználhat a számításhoz. Ebben az esetben a második függvény paraméterei is bekerülnek a verembe, annak adódik át a vezérlés, és így tovább. Az akár több tucatnyi elemből álló láncot hívási veremnek (call stack) nevezzük.
Egy program akár más forrásnyelven írt könyvtár függvényeit is hívhatja, ha egyező hívási módokat használnak. A hívási módot a deklaráció mögötti kulcsszavakkal (cdecl, stdcall) jelöljük.
Egyéb érdekességek[szerkesztés]
Makró[szerkesztés]
Egyes nyelvekben (pl. C) a függvényekhez első látásra nagyon hasonló, úgynevezett makrók is használhatók. Ezeknél fontos tudni, hogy itt nincs szó veremhasználatról, a makrókat az előfordító a "hívás" helyén a makró törzsére cseréli a paraméterek helyettesítésével.
Bizonyos programnyelvek megengedik a hívás nélküli (inline) függvények használatát. Ezek a makrókhoz hasonlóan működnek, azzal a különbséggel, hogy a fordító nem a forráskódban, hanem a lefordított tárgykódban végzi a helyettesítést.
Függvény mint változó értéke[szerkesztés]
Sok programnyelvben (többek közt az összes funkcionális nyelvben) lehetőség van a függvények értékként való kezelésére. Ez lehetővé teszi, hogy a függvényt változóban tároljuk, vagy paraméterként adjuk át más függvénynek. Szigorúan típusos nyelvekben (pl. C, Pascal, C#) a függvény mint érték típusát a szignatúrája (az argumentumok és a visszatérési érték típusai) határozza meg.
Ezt a funkciót gépi kódra fordító nyelvekben általában úgy valósítják meg, hogy a függvény első gépi kódú utasításának a címét tárolják le az adott változóban. Interpreteres nyelvekben a függvényeket egyébként is az interpreter valamilyen belső adatszerkezete reprezentálja, így ennek a címe használható a változó értékeként.
Nézzünk példaképpen egy Python nyelvű számológép programot, ami könnyen bővíthető új műveletekkel:
#Definiáljuk a műveleteket
def add(x, y):
return x+y
def sub(x, y):
return x-y
def mul(x, y):
return x*y
def div(x, y):
return x/y
#A műveletvégző függvényeket a műveleti jelekhez rendeljük egy szótárban
operators = {'+':add, '-':sub, '*':mul, '/':div}
op1 = float(raw_input('Az első operandus:'))
op2 = float(raw_input('A második operandus:'))
operator_str = raw_input('A műveleti jel:')
#Kikeressük a megfelelő függvényt
operator_function = operators.get(operator_str)
if operator_function is None:
print 'Hiba: érvénytelen műveleti jel!'
else:
#Meghívjuk a változóban tárolt függvényt
result = operator_function(op1, op2)
print 'Az eredmény:', result
Példa a függvények paraméterként való átadására: készítsünk függvényt, amely egy másik függvény értékeit számolja ki egy listába!
#A függvény eredménye egy lista a függvény értékeiből a 0..(length-1) egész számokra
def list_function(fun, length):
result = []
for i in range(length):
result.append(fun(i))
return result
#Példa függvény: négyzetre emelés
def square(i):
return i*i
#Példa függvény: Fibonacci számok
def fibo(i):
if i in (0,1):
return i
else:
return fibo(i-2)+fibo(i-1)
print list_function(square, 5) #Kiírás: [0, 1, 4, 9, 16]
print list_function(fibo, 10) #Kiírás: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Egyes nyelvekben lehetőség van úgynevezett névtelen függvények, vagy más néven lambdák használatára. Ezek olyan speciális kifejezések, amelyek egy függvényt adnak értékül; ezt az értéket egyből változóhoz rendeljük, vagy egy másik függvénynek adjuk át argumentumként. Ezt a megoldást akkor szokás alkalmazni, ha az adott függvény viszonylag rövid, és csak egyetlen helyen használjuk a kódban. (Egyéb esetekben rontja az olvashatóságot.)
Függvény példák[szerkesztés]
SearchString[szerkesztés]
Példa Object Pascal nyelven:[szerkesztés]
function SearchString {a függvény neve}
( {argumentumlista}
const Arr: array of String; {konstans argumentum, név és típus}
const Item: String;
CaseSens: Boolean; {érték szerint átadott paraméter}
out Index: Integer {cím szerint átadott kimeneti paraméter}
): Boolean; {a visszatérési érték típusa logikai}
var
i: Integer; {lokális változó}
begin {függvénytörzs kezdete}
for i := 0 to Length(Arr)-1 do begin
{A visszatérési érték (Result) változóként használható}
if CaseSens
then Result := Item = Arr[i]
else Result := 0 = CompareText( Item, Arr[i] );
if Result then begin
Index := i; {a cím szerint átadott paraméter változóként használható}
Exit; {kilépés a függvényből, a vezérlés visszakerül a hívóhoz}
end;
end;
Index := -1;
Result := false;
end;
var
IsThere: Boolean;
Index: Integer;
begin
IsThere := SearchString( ['Bob','Joe','Jim'], 'jim', false, Index );
{a függvény hívása az aktuális paraméterekkel}
end.
Példa Haskell nyelven:[szerkesztés]
stringSearch :: [String] -> String -> Bool -> (Bool,Int)
stringSearch slist str caseSens = res slist (False,0) where
res [] _ = (False, (-1))
res (x:xs) (b,i) = if cond then (cond,i) else res xs (cond,(i+1)) where
cond = (if caseSens then str == x else map toLower str == map toLower x)
main = putStrLn $ show $ stringSearch ["Bob","Joe","Jim"] "Jim" False
Sum[szerkesztés]
Példa Turbo Pascal nyelven:[szerkesztés]
Itt érdekességként elmondható, hogy a függvény visszatérési értékének típusát a fejlécben, az eredményét a függvénytörzsben rögzíteni kell, úgy hogy a függvény azonosítóját az értékadás jel baloldalán kell elhelyezni, majd megadni az értékadás jelet ( :=
) , és meg kell adni azt a kifejezést amely a függvény visszatérési értékének eredménye lesz.
... function_name:= expression; end;
Nézzünk meg egy egyszerű függvényt amely összead 2 számot, amely lehet egész(Integer) és valós (Real) is.
Var n1:Integer;
n2,e:Real;
Function Sum(num1,num2:Real):Real;
Begin
Sum:=num1 + num2;
End;
Begin {main}
n1:=100;
n2:=12.023;
e:=Sum(n1,n2);
End.
Példa Haskell nyelven:[szerkesztés]
sum' :: (Num a, Show a) => a -> a -> a
sum' = (+)
main' = putStrLn $ show $ sum' 100 12.023