HIK Elektronikus Felsőoktatási Tankönyv- és Szakkönyvtár
A Kempelen Farkas Felsőoktatási Digitális Tankönyvtár/vagy más megjelenítő által közvetített digitális tartalmat a felhasználó a szerzői jogról szóló 1999. évi LXXVI. tv. 33. paragrafus (4) bekezdésében meghatározott oktatási, illetve tudományos kutatási célra használhatja fel. A felhasználó a digitális tartalmat képernyőn megjelenítheti, letöltheti, arról elektronikus adathordozóra vagy papíralapon másolatot készíthet, adatrögzítő rendszerében tárolhatja. A Kempelen Farkas Felsőoktatási Digitális Tankönyvtár/vagy más megjelenítő weblapján található digitális tartalmak üzletszerû felhasználása tilos, valamint kizárt a digitális tartalom módosítása és átdolgozása, illetve az ilyen módon keletkezett származékos anyag további felhasználása.

12. Eljárások alapfokon

Oszd meg és szedd szét…

Hernyák Zoltán

Hosszabb programok írása esetén amennyiben a teljes kódot a Main tartalmazza, a program áttekinthetetlen lesz.

Mindenképpen javasolt a kód részekre tördelése. Ennek során olyan részeket különítünk el, amelyek önmagában értelmes részfeladatokat látnak el. E részfeladatoknak jól hangzó nevet találunk ki (pl. bekérés, feltöltés, kiírás, maximális elem megkeresése, listázás, kigyűjtés, stb.), ezeket a program külön részén, a Main fv-től elkülönítve írjuk meg.

Az ilyen, önálló feladattal és névvel ellátott, elkülönített programrészletet eljárásnak nevezzük.

Az eljárásnak

  • a visszatérési érték típusa kötelezően void,

  • van neve (azonosító),

  • lehetnek paraméterei,

  • van törzse.

Pl:

static void Információ()

{

Console.WriteLine("*******************");

Console.WriteLine("** Példa program **");

Console.WriteLine("Programozó: Kiss Aladár Béla");

Console.WriteLine("Készült: 2004.11.23");

}

A fenti példában az eljárás neve ’Információ’, és saját utasításblokkja van (a ’{’ és ’}’ közötti rész). Az eljárás (egyelőre) ’static void’ legyen, és a zárójelpár megadása kötelező abban az esetben is, amennyiben nincsenek paraméterek.

Amennyiben a program adott pontján szeretnénk végre hajtani az eljárásban foglalt utasítássorozatot, úgy egyszerűen hivatkoznunk kell rá a nevével (eljárás indítása, eljárás meghívása):

static void Main(string[] args)

{

Információ();

}

Ekkor az adott ponton az eljárás végrehajtásra kerül, majd a végrehajtás visszatér a hívást követő utasításra, és folytatódik tovább a program futása:

Természetesen van rá lehetőség, hogy ne csak a Main()-ből hívjunk eljárásokat, hanem az eljárásokból is van lehetőség további eljárásokat hívni:

C#-ban az eljárások neve azonosító, ezért érvényes az azonosító névképzési szabálya: betűvel vagy aláhúzással kezdődik, betűvel, számjeggyel, aláhúzás karakterekkel folytatódhat (de nem tartalmazhat szóközt)! A C#-ban szabad ékezetes karaktereket is használni az eljárás-nevekben, de nem javasolt – karakterkészlet és kódlap függő forráskódot eredményez, e miatt másik gépen másik programozó által nehezen elolvashatóvá válik a forráskód.

Hová írjuk az eljárásainkat?

Az Objektum Orientált programozás elvei szerint a programok építőkövei az osztályok. Az osztály (class) mintegy csoportba foglalja az egy témakörbe, feladatkörbe tartozó eljárásokat, függvényeket, változókat. E miatt a program felépítése a következő lehet:

using System;

namespace Tetszoleges_Nev

{

class PeldaProgram

{

Más eljárások ...

static void Main(string[] args)

{

...

}

További eljárások ...

}

}

Az egyéb eljárásainkat ugyanabba a csoportba (osztályba) kell megírni, mint ahol a Main() fv található. A sorrendjük azonban lényegtelen, mindegy, hogy a saját eljárásainkat a Main() fv előtt, vagy után írjuk le, illetve írhatjuk őket vegyes sorrendben is. Az eljárások egymás közötti sorrendje sem lényeges. Ami fontos, hogy közös osztályba (class) kerüljenek.

A programok eljárásokra tagolása persze újabb problémákat szül. Az eljárások ’nem látják’ egymás változóit. Ennek oka a változók hatáskörének problémakörében keresendő.

Minden változónévhez tartozik egy hatáskör. A hatáskör megadja, hogy az adott változót a program szövegében mely részeken lehet ’látni’ (lehet rá hivatkozni). A szabály az, hogy a változók csak az őket tartalmazó blokk-on belül ’láthatók’, vagyis a változók hatásköre az őket tartalmazó blokkra terjed ki.

static void Main(string[] args)

{

int a=0;

Feltoltes();

Console.WriteLine("{0}",a);

}

static void Feltoltes()

{

a=10;

}

A fenti kód hibás, mivel az ’a’ változó hatásköre a ’Main’ függvény belseje, az ’a’ változóra a ’Feltoltes()’ eljárásban nem hivatkozhatunk. Ha mégis megpróbáljuk, akkor a C# fordító a The name 'a' does not exist … kezdetű fordítási hibaüzenettel jelzi ezt nekünk.

Ezt (hibásan) az alábbi módon reagálhatjuk le:

static void Main(string[] args)

{

int a=0;

Feltoltes();

Console.WriteLine("{0}",a);

}

static void Feltoltes()

{

int a=10;

}

Ekkor a ’Feltoltes()’ eljárásban is létrehozunk egy másik, szintén ’a’ nevű változót. Ez a változó sajátja lesz a ’Feltoltes()’-nek, de semmilyen kapcsolatban nem áll a ’Main()’ függvény-beli ’a’ változóval. A nevek azonossága ellenére ez két különböző változó, két különböző adatterületen helyezkedik el. Ezért hiába tesszük bele az ’a’ változóba a ’10’ értéket, ezen érték a ’Feltoltes()’ eljárásbeli ’a’ változóba kerül bele, nem a Main()-beli ’a’ változóba.

Hogyan kell megosztani változókat eljárások között?

Mivel a hatáskör-szabály szigorú, és nincs kivétel, ezért mindaddig, amíg az ’a’ változót a Main() függvény blokkjában deklaráljuk, addig e változót más eljárásokban nem érhetjük el. A megoldás: ne itt deklaráljuk!

class PeldaProgram

{

static int a=0;

static void Main(string[] args)

{

Feltoltes();

Console.WriteLine("{0}",a);

}

static void Feltoltes()

{

a=10;

}

}

Azokat a változókat, amelyeket szeretnénk megosztani az eljárásaink között, azokat az eljárásokat összefogó osztály (class) belsejében, de az eljárásokon kívül kell deklarálni. Mivel az eljárásaink static jelzővel vannak ellátva, ezért a közöttük megosztott változókat is ugyanúgy static jelzővel kell ellátni. Ha ezt elmulasztanánk, akkor a static eljárások nem ’látnák’ a nem static változókat.

Nézzünk egy összetett feladatot: kérjünk be egy tíz elemű vektor elemeit billentyűzetről, majd írjuk ki a vektor elemeinek értékét a képernyőre egy sorban egymás mellé vesszővel elválasztva, majd számoljuk ki és írjuk ki a képernyőre a vektor elemeinek összegét.

Figyeljük meg, hogy a Main() függvény nem tartalmaz lényegében semmilyen kódot, a tényleges műveleteket eljárásokba szerveztük, és jól csengő nevet adtunk nekik:

class PeldaProgram

{

static int[] tomb=new int[10];

static int osszeg=0;

//..................................................

static void Main(string[] args)

{

Feltoltes();

Kiiras();

OsszegSzamitas();

Console.WriteLine("A tomb elemek osszege={0}"

,osszeg);

}

//..................................................

static void Feltoltes()

{

for(int i=0;i<tomb.Length;i++)

{

Console.Write("A tomb {0}. eleme=",i);

string strErtek=Console.ReadLine();

tomb[i] = Int32.Parse( strErtek );

}

}

//.................................................

static void Kiiras()

{

Console.Write("A tomb elemei: ");

for(int i=0;i<tomb.Length;i++)

Console.Write("{0}, ",tomb[i]);

Console.WriteLine();

}

//.................................................

static void OsszegSzamitas()

{

osszeg=0;

for(int i=0;i<tomb.Length;i++)

osszeg = osszeg + tomb[i];

}

//..................................................

}

A változók között meg kellett osztani magát a tömböt, mert azt minden eljárás használta. Ezen túl meg kellett osztani egy ’osszeg’ nevű változót is, mert ezen változó értékét az ’OsszegSzamitas()’ eljárás számolja ki, és a Main() függvény írja ki a képernyőre.