Programok működésének felépítése

Amikor valaki elkezd programozással foglalkozni, programozást tanulni, akkor mindig az első leckék között szerepel, hogy megértsük, hogy hogyan is működnek a programok. Milyen sorrendben hajtódnak végre egymás után az utasítások, hogyan épül fel egy program.

 

Egy program nem más, mint utasítások szekvenciális végrehajtásának halmaza.

Kezdjük a legegyszerűbb eshetőséggel, az egyszálú programokkal. Mit jelent ez?
Azt, hogy van egy fő szál, ami szekvenciálisan hajtja végre az egymás után következő utasításokat. Nézzünk erre egy példát:

int a = 2;

int b = 3;

int c, d;

c = a+b;

d = c*a;


Hogyan fognak egymás után lefutni az utasítások?

Felülről lefelé. Először létrejönnek egymás után a változók „a”, „b”, „c” és „d”. A változók vagy úgy jönnek létre, hogy van valamilyen dedikált kezdőértékük („a”, „b”) vagy úgy, hogy csak létrejön, de nem kap értéket („c”, „d”). Ezután kiszámoljuk „c” értékét majd végül pedig „d” értékét. Nincsenek kereszthatások és nincsenek ugrások sem. Mi történik, ha megcserélem „c” és „d” kiszámításának sorrendjét?

Mivel „d”-nek bemenete „c”, de mivel „c” csak „d” után kap számolt értéket, ezért nem tudjuk megmondani pontosan, hogy mi lesz „d” értéke. Azonban a program továbbra is működőképes marad, de biztosan kapunk egy hatalmas figyelmeztető üzenetet, hogy úgy használunk fel egy változót, hogy annak értékét mi magunk még sosem állítottuk. De hogyan lehetséges ez?
Úgy, hogy valamilyen előre nem definiált értéket minden változó kap a létrehozásakor, ha mi magunk nem állítunk be semmilyen kezdőértéket. Ez az érték igazából bármi lehet, nem lehet előre megmondani. Ez egy nagyon gyakori hiba és veszélyes szituáció, éppen ezért komoly figyelmeztetéseket küld ilyen esetben a fordító és a fejlesztő környezet is, ha észreveszi. Éppen ezért a legjobb megközelítés, amit én mindenkinek kifejezetten ajánlani szoktam, hogy mindig minden változónak adjunk kezdőértéket! Ez sokszor feleslegesnek tűnik, de ha egyszer bekerül a napi rutinba akkor sok fejfájást meg tudunk spórolni.


Függvények

Egy jól strukturált kód első ismérve a függvények megfelelő minőségű és mennyiségű használata. Mi is pontosan egy függvény?
A programozásban használt függvények analóg módon működnek a matematikában megszokott függvényekhez. Azaz valamilyen bemeneti adatokból valamilyen módon előállít kimeneti adatot vagy adatokat, áttranszformálja a bemeneti adatokat kimeneti adatokká. Azt, hogy ezt pontosan hogyan teszi, az már a függvénynek a belső hatásköre. Ezért ami fontos, hogy minden függvénynek (mostmár a programozásbeli függvényekről beszélek) kell, hogy legyen egy jól definiált bemeneti és kimeneti leírása. Pontosan milyen bemeneti adatokból milyen kimeneti adatokat fog előállítani. Persze a belső működésének a leírása is mindig szükséges, de vannak olyan szituációk amikor az nem feltétlenül fontos számunkra, csakis a bemenetek és a kimenetek.


Hogyan néz ki egy függvény deklarációja a programozásban?

VisszatérésiÉrtékTípusa FüggvényNév(Parameter1Típusa Parameter1, Parameter2Típusa Parameter2, …, ParameterNTípusa ParameterN) { … }


Deklaráljuk az összeadás függvényt, ami 2 számot ad össze:

int SumOfTwoNumbers( int Number1, int Number2) { … }

VisszatérésiÉrtékTípusa int
FüggvényNév SumOfTwoNumbers
Parameter1Típusa int
Parameter1 Number1
Parameter2Típusa int
Parameter2 Number1



Minden függvénynek kötelező, hogy legyen be és kimenete is?

Az elképzelhető, hogy nincs semmilyen bemenete, egyszerűen a semmiből állít elő valamilyen adatot, például van egy függvényem ami mindig visszaadja, hogy mennyi 2+3. De se a 2, sem pedig a 3 nem bemenete a függvénynek. Azonban olyan, hogy egy függvénynek semmilyen kimenete nincs, az már nehezen elképzelhető. Lehet, hogy a kimenete nem egy jól megfogható dolog, mint például egy visszatérési érték, hanem csak valami elvontabb cselekvés, például kiír valamit a képernyőre. De mindig kell, hogy legyen valamilyen kimenet. Ha nincs, akkor felmerül a kérdés, hogy miért létezik egyáltalán ez a függvény, mi a célja?

Minden program tehát változókból és függvényekből épül fel. Nézzük meg az előző példát, összeadó és szorzó függvények segítségével:

int a = 2;

int b = 3;

int c, d;

c = SumOfTwoNumbers(a,b);

d = MultiplicationOfTwoNumbers(c,a);


Képzeljük el, hogy a fenti program egy komoly projekt eredménye. A projekten ketten dolgoznak. A függvények használhatóságának hála tudtak egymással párhuzamosan dolgozni. Amíg az egyik kolléga megírta a demo programot, addig a másik el tudta készíteni az összeadó és összeszorzó függvényeket, amit így már csak hívogatni kellett.

Így már kicsit érthetőbb, hogy mik az óriási előnyei a függvényeknek? A párhuzamosítás. Képzeljük el, hogy van egy projekt amin 50-en dolgoznak egyszerre. Hogyan lehetne szervezni a munkát, ha nem lehetne függvényeket használni? A mai komplexitású programoknál ez a strukturáltság elengedhetetlen.


Mikor jó egy kód?

Ez egy örök kérdés, amire sohasem lesz meg a tökéletes válasz. Egészen egyszerűen azért, mert rengeteg feladat létezik amire rengeteg féle megoldást lehet adni. Nincs tökéletes megoldás és tökéletes kód sem általában. Azonban ma már egész jó mérőrendszerek léteznek, ez az úgynevezett statikus kód analízis. Ennek lényege, hogy különböző mérőszámokat állít elő a forráskódról és vannak tipikus értékek, hogy mikor jó egy forráskód. Ilyen analizáló SW például, ami ingyenesen elérhető Eclipse Plugin formájában a Checkstyle Java kódra vagy a Codan C kódra.


Vannak tehát az egyszálú programok, amiknek a futása, végrehajtási sorrendje viszonylag egyértelmű. Vannak azonban a több szálú programok, amikor a program különböző végrehajtási szálai egymással párhuzamosan futnak.
Ekkor létezik egy fő szál és léteznek a fő szálban létrehozott mellékszálak. Ha a fő szál véget ér, akkor a mellékszálak is automatikusan megszűnnek. Ez egy külön programozási technológia, rengeteg extra lehetőséggel és potenciális veszéllyel is az egyszálú programokhoz képest.

Létezik ennek egy kicsit más megközelítése, amikor a program maga egyszálú, de a programból több példány fut egyszerre párhuzamosan.
Ilyenre példa a webes alkalmazások és az azokat futtató webszerverek. Például ha van egy webes dokumentum szerkesztő, akkor azt egyszerre sok tíz vagy százezren is használhatják, de mindenki ugyanazt az egy programot használja. Ennek eggyel izgalmasabb verziója amikor többen használják ugyanazt a programot, ilyenek például a számítógépes játékok az interneten.



Ezek tehát a programok felépítésének és futtatásának legalapvetőbb verziói. Remélem sikerült egy tisztább képet kialakítani magatokban a függvények fontosságáról. Amikor még ismerkedünk a programozással akkor én mindenképpen a legegyszerűbb verziók megértését ajánlom először. Ha azt már tökéletesen értjük, akkor lehet feljebb építkezni. De mi az a szint amit el kell érnünk és hogyan tudjuk ezt hatékonyan megtenni?

Ha pedig 110%-ra kapcsolnál, akkor nézd meg a  Java Tanfolyamomat! Tetszeni fog!

Bajor Tamás - Programozz Te Is!

Szia, Bajor Tamás vagyok, a Programozz Te Is oldal alapítója és oktatója. Köszi, hogy itt vagy és éppen az én cikkem olvasására fordítod a drága idődet! Azért dolgozom minden nap, hogy neked segítsek a programozás világában minél profibban elmélyülni. A cikkek egyetlen írójaként rengeteg munkát és energiát fektetek mind az oldalba, mind pedig az oktatásba!

Arra kérlek, ha tetszett cikk amit olvastál vagy szívesen veszed az ingyenes anyagokat akkor dobj egy Like-ot a Facebook-on, ezzel is támogatva a munkámat. Neked ez egy apró kattintás, nekem pedig hatalmas segítség!