Függvények, eljárások

 

Definiálás:

 

Visszatérési_típus  függvény_neve( formális_paraméterek )     //A függvény fejléce (fejlécsora).

{

    

 

//A függvény törzse: ide írjuk a függvény kódját (műveleteit)

    

 

     return eredmény;    //Így adjuk vissza az eredményt, befejezve a függvény működését.

}

 

Visszatérési_típus: a függvény által kiszámolt eredményt itt szoktuk visszaadni.

A függvény_ neve.

A formális_paraméterek: a függvény meghívásakor itt szoktunk átadni adatokat ill. változó hivatkozásokat, amelyek felhasználása befolyásolhatja a függvény működését.

 

 

Pl:  Írjunk egy függvényt, amelyik paraméterként kap két egész számot, és eredményként megadja a kettő közül a nagyobbikat. Legyen a függvény neve max, paraméterként kapjon két egész számot, ezek közül kell a nagyobbiknak az értékét visszaadni, amely szintén egy egész szám, tehát a függvény vissza térési típusa is egész lesz.

 

 

int   max( int a, int b )

{

     int eredmeny;     // lokális változó, csak a függvényen belül látható.

 

     if ( a>b )

          eredmény = a;

     else

          eredmeny = b;

 

     return eredmeny;   //itt ér véget a függvény működése és itt adjuk vissza az eredményt is.

}

 

 

 

A return hatására kilépünk a függvényből, tehát az előző példában nem szükséges bevezetnünk egy lokális változó:

 

int   max( int a, int b )

{

     if ( a>b )

          return a;   //az eredmény legyen a értéke

     else

          return b;   //az eredmény legyen b értéke

}

 

 

 

 

Felhasználás:

A függvények felhasználását a kódban meg kell előznie a deklarálásuknak (vagy teljes definiálásuknak).

Deklarálás: A függvény fejlécsorának a megadása pontosvesszővel lezárva (a paraméterek neveit nem kell megadni csak a típusát).

 

Pl.: Írjunk programot, amelyik két beolvasott egész szám közül kiírja a nagyobbikat.

 

 

#include <iostream>

 

using namespace std;

 

int max( int, int );   //Itt deklaráljuk a függvényt.

 

int main()

{

    int a,b;

 

    //Beolvassuk a két számot

    cout << "Kerem az egyik szamot: ";

    cin >> a;

    cout << "Kerem a masik szamot: ";

    cin >> b;

 

    cout << "A nagyobbik szam: " << max(a,b) << endl;    //Itt hívjuk meg a függvényt, és eredményét kiírjuk.

 

    return 0;

}

 

 

//Itt van a függvény definiálása:

int   max( int a, int b )

{

     if ( a>b )

          return a;

     else

          return b;

}

 

 

Eljárás: olyan függvény, amelynek nincs visszatérési típusa. Ekkor a visszaérési típusnak a void kulcsszót kell írni.

Pl.:   void eljaras( formális paraméterek );

Az eljárásnál is használhatjuk a return utasítást az eljárásból való kilépésre, csak utána pontosvesszőt írjunk és ne egy kifejezést.

 

void   eljaras( int a, int b )

{

     //Ide valamilyen tevékenység et írunk.

 

     return;  //Itt lépünk ki az eljárásból.

}

 

 

 

Paraméterátadás:

 

Kétféle paraméterátadást fogunk használni:

 

1. Érték szerinti paraméterátadás: a formális paraméterlistán megadott paraméterből keletkezett lokális változóba másolódik a híváskor megadott aktuális paraméter értéke. A lokális változó értékén történő bármely változtatásnak semmi kihatása sincs a híváskori aktuális paraméterváltozó értékére.

Megadása: típusnév paraméter_név

Pl:   a lenti programot futtatva:

 

void fv( int a)  //az a változó felveszi a híváskori értéket, 10-et (lásd main())

{

     a = a+1;                //Itt a-t növeljük eggyel, azaz a==11

     cout << a << endl;     //Itt kiírjuk a 11-et

}

 

 

int main()

{

     int  x = 10; 

     fv(x);             //x akt. paraméterrel hívjuk fv-t, x értéke bemásolódik a lokális a változóba

     cout << x << endl; //x értéke nem változik meg a függvényhívás során, tehát 10-et ír ki.

}

 

 

2. Hivatkozás szerinti paraméterátadás: formális paraméterlistán megadott paraméterből keletkezett lokális változóba egy hivatkozás kerül a híváskor megadott aktuális paraméterre. Tekinthetjük úgy is, hogy az aktuális paraméternek megadott változót egy másik (lokális) néven keresztül is elérhetjük. A lokális változó értékén történő változtatás a híváskori aktuális paraméter változó értékékén változtat.

Megadása: típusnév &paraméter_név

 

void fv( int &a)  //az a változó egy hivatkozás lesz a híváskori paraméterváltozóra

{

     a = a+1;                //Itt a-t növeljük eggyel, azaz a==11

     cout << a << endl;     //Itt kiírjuk a 11-et

}

 

 

int main()

{

     int  x = 10; 

     fv(x);             //x akt. paraméterrel hívjuk fv-t, x-re hivatkozik a lokális a változó

     cout << x << endl; //x értéke megváltozott függvényhívás során, tehát 11-et ír ki.

}

 

 

 

Mikor melyiket használjuk?

Ebben a félévben, hivatkozás szerinti paraméterátadást, akkor használjunk, ha olyan eljárást vagy függvényt írunk ahol az eredményt paraméter útján szeretnénk visszaadni, vagy azt szeretnénk, hogy az eljárás vagy függvény módosítsa a paraméterként adott változót. Különben használjunk értékszerinti paraméterátadást. (Ettől csak a tömböknél térjünk el, lásd később.)

 

 

 

Példák hivatkozás szerinti paraméterátadásra:

 

 

Írjunk eljárást, amely beolvas egy egész számot. A függvény felhasználásával a több számot beolvasó kód egyszerűsíthető, mivel a beolvasó eljárást csak egyszer kell megírni.

 

#include <iostream>

#include <string>

 

using namespace std;

 

void beolvas(string szoveg, int &a);  //az a változón keresztűl adjuk vissza a beolvasott számot

 

int main()

{

    int x,y;

 

    beolvas( "Kerem az egyik szamot: ", x ); //Beolvasás az x-be hivatkozáson keresztül

    beolvas( "Kerem az masik szamot: ", y ); //Beolvasás az y-ba hivatkozáson keresztül

 

    cout << "A ket szam osszege: " << x+y << endl;

 

    return 0;

}

 

 

void beolvas(string szoveg, int &a)

{

    cout << szoveg;  //Kiírjuk a kapott szöveget

    cin >> a;       //Beolvassuk a számot

}

 

 

 

Írjunk eljárást, amely megcseréli két egész típusú változó tartalmát:

 

#include <iostream>

#include <string>

 

using namespace std;

 

void csere( int &a, int &b );

void beolvas(string szoveg, int &a);  //az a valtozóban adjuk vissza a beolvasott szamot

 

 

int main()

{

    int x,y;

 

    beolvas( "Kerem az egyik szamot: ", x ); //Beolvasás az x-be hivatkozáson keresztül

    beolvas( "Kerem az masik szamot: ", y ); //Beolvasás az y-ba hivatkozáson keresztül

 

    csere(x,y);  //itt cseléjük fel a két változó tartalmát.

 

    cout << "x: " << x << endl;

    cout << "y: " << y << endl;

 

    return 0;

}

 

 

void csere( int &a, int &b ) 

{

    int temp = a;

    a = b;

    b = temp;

}

 

 

void beolvas(string szoveg, int &a)

{

    cout << szoveg;  //Kiírjuk a kapott szöveget

    cin >> a;       //Beolvassuk a számot

}

 

 

 

Tömbök használata függvényekben:

 

A tömb paraméterek „hivatkozás” szerint adódnak át. Mivel a tömb nem „tudja” a méretét, ezért a méretét külön paraméterben adjuk át. A tömb paramétereket a következő módokon használjuk:

 

1. Ha a tömb elemeinek a számát változtatni akarjuk (pl. a tömböt fel akarjuk tölteni):   típus FV( tömb_elem_típus  v[],  int &db  );  

v tömb típusú paraméter hivatkozás szerinti paraméter átadással (még ha nem is jelöljük),db-t is hivatkozás szerint adjuk át

            Pl.:   void beolvas( int v[], int &db );

 

2. Ha meg akarjuk változtatni a tömb tartalmát, de az elemek száma nem változik:   típus FV( tömb_elem_típus  v[],  int db  ); 

v tömb típusú paraméter hivatkozás szerinti paraméter átadással (még ha nem is jelöljük),db-t érték szerint adjuk át

            Pl.: void rendez( int v[], int db);

 

3. Ha nem akarjuk megváltoztatni a tömb tartalmát:   típus FV( const tömb_elem_típus  v[],  int db  );

v tömb típusú paraméter hivatkozás szerinti paraméter átadással (még ha nem is jelöljük), de a const jelző miatt v elemit nem tudjuk változtatni, db-t érték szerint adjuk át

Pl.: void kiir( const int v[], int db);

 

 

Tehát a tömböknél nem kell használni a hivatkozás & jelet, mégis hivatkozás szerint adódnak át.  Ha a tömböt const-ként adjuk át, akkor a tartalmát nem tudjuk változtatni (a tömb változón keresztül).

 

 

 

Függvény visszatérési értéke:

 

A return után megadott kifejezéssel lehet egy visszatérési értéket megadni.

Pl.: egy egészet visszaadó függvény:

 

int FV( paraméterek )

{

    

     return 5;

}

 

 

Ha több értéket is szeretnénk visszaadni, azt összetett típussal tudjuk megtenni:

 

struct eredmeny{

     int x,y;

};

 

eredmeny FV( paraméterek )

{

     eredmeny e;

     e.x = 1;

     e.y = 0;

     return e;

}

 

Ebben félévben ne használjunk a visszatérési típusoknál módosítókat (pl. referencia).

 

 

 

 

 

Egy példa függvények használatára:

 

Feladat: Adjuk meg egy egynél nagyobb természetes szám prímtényezős felbontását.

 

Specifikáció:

 

Be:       x: N

Ki:       v: Sorozat(N)       //természetes számokból álló sorozat, indextartománya legyen [1..n]

Ef:        x>1

Uf:      

 

 

 

A programban definiáljunk 3 függvényt: a beolvasásra, a prímtényezős felbontásra és az eredmény kiírására.

A feladat specifikációjában és a megoldásban a prímtényezők tárolására egy sorozatot használtunk. Az implementációban ez a sorozat legyen egészekből álló tömb.

A tömböt két változóval tudjuk reprezentálni, az egyik „maga a tömb” (előre beállítva egy max méretre), a másik a tömb elemeinek a száma.

int v[MAX_DB]; int db;

 

Megoldandó probléma a sorozat használt műveleteinek a megadása a tömbre:

 

v := ÜresSorozat   -  üressé teszi v-t (kiüríti)

Egyszerűen a tömb elemeinek számát állítsuk 0-ra

db = 0;

 

v.Hozzáfűz(i)    ami a v sorozathoz hozzáfűzi i-t

Írjuk be a tömb következő szabad helyére i-t és a tömb elemeinek a számát növeljük 1-gyel:

v[db] = i;

db = db +1;

ez rövidebben:

v[ db++ ] = i;

 

 

//-------------------------------------------------------------------------

 

 

#include <iostream>

 

using namespace std;

 

const int MAX_DB = 100;   //a tömb elemeinek max száma, ennyi helyet foglalunk le

 

void beolvas(int &x);

void felbontas(int x, int v[], int &db);

void eredmenyt_kiir(int x, const int v[], int db);

 

 

 

int main()

{

    int v[MAX_DB];

    int db;

    int x;

 

    beolvas(x);             //beolvassunk x változóba

    felbontas(x,v,db);      //elvégezzük x prímtényezős felbontását v-be

    eredmenyt_kiir(x,v,db); //kiirjuk a primtényezőket

 

    return 0;

}

 

 

 

//Beolvassa az egynél nagyobb természetes számot

void beolvas(int &x)

{

    do

    {

        cout << "Kerem az 1-nel nagyobb termeszetes szamot: ";

        cin >> x;

    } while( x<2 );  //akkor ér véget a ciklus, ha x>=2

}

 

 

 

//x primtényezős felbontása, v tömbbe lesznek a prímek

void felbontas(int x, int v[], int &db)

{

    db = 0;

    int i=2;

    while( i<=x )

    {

        if( x%i == 0 )

        {

            v[ db++ ] = i;

            x/=i;

        }

        else

            ++i;

    }

}

 

 

 

//kiirjuk az eredményt

void eredmenyt_kiir(int x, const int v[], int db)

{

 

    cout << x << " felbontasa: " << endl;

    for( int i=0; i<db; ++i)

         cout << v[i] << endl;

}

 

 

/-------------------------------------------------------------------------

 

 

 

 

Gyakorlásképpen a korábbi gyakorlatok feladatait oldjuk meg függvények/eljárások felhasználásával. A programot tagoljuk legalább három különálló részre:

- input adatok beolvasása

- feladat megoldása

- eredmények kiírása

Ezeket a feladattól függően tovább lehet bontani kisebb eljárásokra/függvényekre.

 

 

 

Megjegyzések:

- A függvény nevének és a hozzá tartozó paramétereknek együtt kell egyedinek lenni, azaz definiálhatunk azonos nevű függvényeket, különböző paramétertípusokkal ill. paraméterszámmal.

Pl.:   csere függvény különböző típusokra:
void csere( int &a, int &b);
void csere( string &a, string &b);

- A visszatérési típus nem számít a függvény egyediségénél. Tehát azonos nevű és paraméterű, de különböző visszatérési értékű függvényeket is azonosnak látja a fordító, hibát jelez.

- Ne használjunk pointereket (paraméterátadáshoz, visszatérési típusnál), ebben a félévben nincs szükség a pointerekre.

- Ne használjunk referenciát visszatérési típusként, a lokális változókra való hivatkozási hibák elkerülésére, inkább referencia paramétert használjunk az eredmény visszaadására.

 

 

 

Feladatok:

 

  1. Írjon programot, amely egy egész számokból álló tömb minden elemét megnöveli egy számmal!
  2. Írjon programot, amely egy szöveg betűit egymás alá írja ki a képernyőre!
  3. Írjon programot, amely egy egész számokból álló tömb elemei eggyel balra lépteti, a legelső elem kilép a tömbből, elveszítjük, jobbról pedig egy 0 szám lépjen be!
  4. Írjon programot, amely egy tömb elemeit eggyel balra lépteti ciklikusan, a legelső elemből a legutolsó lesz!
  5. Írjon programot, amely megadja a Fibonacci sorozat első n elemét! ( F1 := 1;  F2:=1;   Fn := Fn-1 )
  6. Írjon programot, amely egy tömb elemeinek a sorrendjét megfordítja!
  7. Írjon programot, amely kiszámítja egy vektor és egy skalár szám szorzatát!
  8. Írjon programot, amely kiszámítja két vektor skaláris szorzatát!
  9. Írjon programot, amely kiszámítja egy vektor hosszát (euklideszi norma)!
  10. Írjon programot, amely egy mátrix két sorának elemeit megcseréli!
  11. Írjon programot, amely egy mátrix két oszlopának elemeit megcseréli!
  12. Írjon programot, amely egy négyzetes mátrixot transzponál!
  13. Írjon programot, amely két mátrixot összead!
  14. Írjon programot, amely két mátrixot összeszoroz!
  15. Írjon programot, amely eldönti egy számról, hogy tökéletes szám-e! Tökéletes számnak nevezzük azokat a természetes számokat, amelyek megegyeznek osztóik összegével (az 1-et beleértve, önmagukat kivéve).
  16. Írjon programot, amely eldönti egy számról, hogy hiányos szám-e t! Hiányos számnak nevezzük azokat a természetes számokat, amelyek nagyobbak az osztóik összegénél (az 1-et beleértve, önmagukat kivéve).
  17. Írjon programot, amely eldönti egy számról, hogy bővelkedő szám-e! Bővelkedő számnak nevezzük azokat a természetes számokat, amelyek kisebbek az osztóik összegénél (az 1-et beleértve, önmagukat kivéve).
  18. Írjon programot, amely kiírja n-nél kisebb tökéletes számokat!
  19. Írjon programot, amely kiírja n-nél kisebb hiányos számokat!
  20. Írjon programot, amely kiírja n-nél kisebb bővelkedő számokat!
  21. Írjon programot, amely eldönti egy számpárról, hogy barátságos számok-e! Azokat a számpárokat, amelyekre igaz, hogy az egyik szám önmagánál kisebb (az 1-et is beleértve) osztóinak összege a másik számmal egyenlő (és fordítva), barátságos számoknak hívjuk.
  22. Írjon programot, amely kiírja n-nél kisebb barátságos számpárokat!
  23. Írjon programot, ami kiírja a prímszámokat 2-től n-ig!