KURZUS: Számítási módszerek
MODUL: Excel programozás
3. lecke: Vezérlőszerkezetek, szubrutinok
Cél: Ebben a leckében a programozás során használt vezérlőszerkezetekkel és a szubrutinokkal fogunk megismerkedni. A hallgató a lecke elsajátítása után már önállóan is meg fog tudni írni kisebb programokat. | |||||||||||||||
Követelmények: Ön akkor sajátította el megfelelően a tananyagot, ha képes | |||||||||||||||
| |||||||||||||||
Időszükséglet: A tananyag elsajátításához (az önálló programozási feladatok megoldása nélkül) hozzávetőlegesen 6 órára lesz szüksége. | |||||||||||||||
Kulcsfogalmak | |||||||||||||||
| |||||||||||||||
Vezérlőszerkezetek | |||||||||||||||
Az eddigiekben szó volt a változók deklarálásáról, az értékadó utasításról, az adatbekérő és adatkiíró lehetőségekről, így ezekből már összeállíthatunk egy olyan programot, amely bizonyos bemenő adatokból valamilyen eredményadatokat számol és ezeket meg is jeleníti. A megfelelő utasításokat ilyenkor egyszerűen sorban egymás után (szekvenciálisan) megadjuk, illetve végrehajtatjuk. | |||||||||||||||
De mi van akkor, ha egy utasítást csak egy adott feltétel teljesülése esetén kell végrehajtani, vagy ha egy utasítást többször is végre szeretnénk hajtani? Szükségünk van olyan eszközökre, amelyekkel az egyes tevékenységek végrehajtási sorrendje előírható. Ezeket az eszközöket vezérlőszerkezeteknek nevezzük. | |||||||||||||||
A strukturált programozás három vezérlőszerkezet használatát engedi meg, ezek a szekvencia, a szelekció és az iteráció. Bizonyítottan minden algoritmus megadható ezekkel a vezérlőszerkezetekkel, ezért a feladatok megoldásánál mi is csak ezeket fogjuk használni. | |||||||||||||||
| |||||||||||||||
Megjegyzés | |||||||||||||||
| |||||||||||||||
Szekvencia | |||||||||||||||
A szekvencia vezérlőszerkezetben a program utasításai (algoritmus esetén ez egyes lépések, tevékenységek) egymást követően, az utasítások megadási sorrendjében hajtódnak végre. A VB-ben az egyes utasításokat általában külön sorokba írjuk, de egy sorba több utasítást is írhatunk, ekkor az utasítások közé kettőspontot kell tenni. | |||||||||||||||
Gondolja át, hogy mit csinál a következő programrészlet! | |||||||||||||||
'Utasítások megadása egy sorban (végrehajtás: balról jobbra haladva) | |||||||||||||||
'Utasítások megadása egymást követő sorokban (végrehajtás: fentről lefelé) | |||||||||||||||
Megjegyzés | |||||||||||||||
| |||||||||||||||
Szelekció | |||||||||||||||
A szelekció vezérlőszerkezet segítségével a végrehajtandó utasítások között szelektálhatunk, azaz megadhatjuk, hogy mikor melyik utasítás, illetve utasítások hajtódjanak végre. Az alábbiakban azt a szelekciós utasítást ismertetjük, amelyben a végrehajtandó utasítások (statements) logikai kifejezésekkel (condition) választhatók ki. | |||||||||||||||
Az If utasítás szintaktikája: | |||||||||||||||
If condition Then [statements] [Else elsestatements] | |||||||||||||||
vagy | |||||||||||||||
If condition Then | |||||||||||||||
Az első esetben az egész utasítás egy sorba kerül (ekkor nem kell End If az utasítás végére), míg a második esetben több sorba (ahol az egyes ágakban lévő utasítások beljebb tagolása nem kötelező, de javítja az áttekinthetőséget). | |||||||||||||||
Végrehajtás: | |||||||||||||||
| |||||||||||||||
Gondolja át, hogy mit csinál a következő programrészlet! | |||||||||||||||
If d = 0 Then | |||||||||||||||
Megjegyzés | |||||||||||||||
| |||||||||||||||
Iteráció | |||||||||||||||
Az iteráció vezérlőszerkezet segítségével egy vagy több utasítás ismételt végrehajtása valósítható meg. Azokat az utasításokat, amelyeket az iteráció (vagy más néven ciklus) ismételten végrehajt, ciklusmagnak nevezzük. Három alapvető ciklusfajta létezik: az elöltesztelő, a hátultesztelő és a növekményes ciklus. | |||||||||||||||
Az elöltesztelő ciklus a ciklust vezérlő feltételt a ciklusmag végrehajtása előtt vizsgálja, a hátultesztelő ciklus pedig a ciklusmag végrehajtása után. A növekményes ciklus egy speciális elöltesztelő ciklus, amely a ciklusmagot egy változó adott értékei mellett hajtja végre. | |||||||||||||||
Mivel a ciklusszervezés a programozás egyik alapvető eleme, ezért a magas szintű programozási nyelvek (így a VB is) mind a három ciklusfajtát támogatják. Ez lehetővé teszi, hogy az adott feladathoz legjobban illeszkedő ciklusfajtát válasszuk, amivel a megoldásunk (programunk) érthetőbb és áttekinthetőbb lesz, de megjegyezzük, hogy az elöltesztelő ciklussal a másik két ciklusfajta is megvalósítható. | |||||||||||||||
A VB ciklusszervező utasításait ismertetjük a továbbiakban. | |||||||||||||||
A While ciklus szintaktikája: | |||||||||||||||
While condition | |||||||||||||||
Végrehajtás: | |||||||||||||||
| |||||||||||||||
Megjegyzés: A ciklusmag utasításainak hatással kell lennie a feltétel igazságértékére (ez a Do ciklusra is érvényes), különben a ciklus üres ciklus, vagy végtelen ciklus (ekkor a Ctrl+Break vagy az Esc billentyűkkel leállítható a programfutás). | |||||||||||||||
Gondolja át, hogy mit csinál a következő programrészlet! | |||||||||||||||
i = 1 | |||||||||||||||
A For ciklus szintaktikája: | |||||||||||||||
For counter=start To end [Step step] | |||||||||||||||
Végrehajtás: | |||||||||||||||
| |||||||||||||||
Gondolja át, hogy mit csinál a következő programrészlet! | |||||||||||||||
For i = 1 To 5 Step 2 | |||||||||||||||
Megjegyzés: A VB-ben létezik egy olyan speciális ciklusszervező utasítás is (For Each), amelyben a ciklusváltozó egy gyűjtemény objektumain "lépdel végig". | |||||||||||||||
A Do ciklus szintaktikája: | |||||||||||||||
Do [{While|Until} condition] | |||||||||||||||
vagy | |||||||||||||||
Do | |||||||||||||||
Végrehajtás: | |||||||||||||||
| |||||||||||||||
A Do utasítás tehát egy olyan általános ciklusszervező utasítás, amellyel mind az elöltesztelő, mind a hátultesztelő ciklusfajta megvalósítható, ráadásul úgy, hogy a feltétellel megadhatjuk az ismétlés, illetve a kilépés feltételét is. | |||||||||||||||
Megjegyzés | |||||||||||||||
| |||||||||||||||
Szubrutinok | |||||||||||||||
Szubrutinon egy jól meghatározott, önálló tevékenységsort megvalósító, formailag is elkülönülő programrészt értünk. A szubrutinok tényleges végrehajtásához általában egy másik, a szubrutint aktivizáló, azt meghívó programrész is szükséges. Egy szubrutin többször is meghívható, így annak szolgáltatásai a program megfelelő helyein egy-egy hívással igénybe vehetők. | |||||||||||||||
A szubrutin a programtervezés, illetve programozás alapszintű, de egyben alapvető fontosságú eszköze. Használatukkal érvényesíthető az egységbezárási elv, miszerint egy adott feladat megoldásához szükséges adatoknak és a "rajtuk dolgozó" algoritmusnak egy olyan egysége valósítható meg, amely csak a szükséges mértékben kommunikál a "külvilággal", a szubrutint hívó programrészekkel, egyébként zárt, "dolgait" saját maga "intézi", azokba "nem enged bepillantást". | |||||||||||||||
Megkülönböztetjük a szubrutin deklarálását, ahol definiáljuk a szubrutin által végrehajtandó tevékenységeket, a külvilággal való kapcsolattartás módját és szabályait, valamint a szubrutin hívását, amikor felhasználjuk a szubrutin szolgáltatásait, vagyis definiálva a kapcsolattartás eszközeit, kiváltjuk a tevékenységsor egy végrehajtását. | |||||||||||||||
A kapcsolattartás legfőbb, de nem kizárólagos (hiszen pl. "mindenhonnan látható" (public) változókon keresztül is történhet a kommunikáció) eszközei a paraméterek. | |||||||||||||||
A helyes programozási stílus a teljes paraméterezésre való törekvés. Ez azt jelenti, hogy egy szubrutin a működéséhez szükséges adatokat a paraméterein keresztül kapja, és az eredményeket (a függvényérték kivételével) ezeken keresztül adja vissza. Ezzel ugyanis elkerülhető egy esetleges módosítás olyan "mellékhatása", amely a program egy "távoli részének" végrehajtásakor, előre nem látott, nem tervezett változást, s ezzel többnyire nehezen felderíthető hibát okoz. | |||||||||||||||
Megjegyzés | |||||||||||||||
| |||||||||||||||
Deklaráció és hívás | |||||||||||||||
Kétféle szubrutint különböztetünk meg, az eljárást és a függvényt. Az eljárást általában akkor használjuk, ha valamilyen tevékenységet kell végrehajtanunk, a függvényt pedig akkor, ha valamilyen eredményértéket kell kiszámolnunk. | |||||||||||||||
Mivel mind az eljárás, mind a függvény képes adatokat kapni és eredményadatokat visszaadni, így egy adott szubrutin eljárás, illetve függvény alakban is programozható. Az, hogy egy szubrutint eljárás vagy függvény formájában írunk meg, nem elvi kérdés, inkább programozói stílus kérdése. A két forma egymással ekvivalens módon mindig helyettesíthető. Az eljárások és függvények deklarálása és hívása, ha kicsit is, de eltérő. | |||||||||||||||
Deklarálás | |||||||||||||||
Eljárás deklarálásának (egyszerűsített) szintaktikája: | |||||||||||||||
[Private|Public] Sub name[(arglist)] | |||||||||||||||
Függvény deklarálásának (egyszerűsített) szintaktikája: | |||||||||||||||
[Private|Public] Function name[(arglist)] [As type] | |||||||||||||||
| |||||||||||||||
Vegyük észre, hogy a függvény utasításai között szerepel egy olyan értékadó utasítás is, amivel a függvény nevének (name) mint változónak adunk értéket. Ez az utasítás szolgál a függvény eredményének a beállítására. Több ilyen utasítás is elhelyezhető a függvény utasításai között, de célszerű egyet elhelyezni, azt is a függvény végén, azaz az End Function utasítás előtt. | |||||||||||||||
A formális paraméterek megadásának szintaktikája: | |||||||||||||||
[Optional][ByVal|ByRef][ParamArray]varname[()][As type][=defaultvalue] | |||||||||||||||
| |||||||||||||||
A paraméterek neve előtt álló kulcsszavakkal a paraméterek elhagyhatósága, valamint a paraméterek átadási módja definiálható. Az érték szerinti (ByVal) paramétereken keresztül a szubrutin csak kaphat adatokat, míg a cím szerinti átadású (ByRef) paramétereken keresztül kaphat is adatokat, és vissza is adhat eredményeket. Ezért a ByVal paramétereket a szubrutin bemenő (input) adatainak megadásához, a ByRef paramétereket pedig a szubrutin bemenő és/vagy kimenő (output) adatainak megadásához használhatjuk. | |||||||||||||||
Megjegyzés: | |||||||||||||||
| |||||||||||||||
Próbálja ki a Vezérlőszerkezetek fejezetben bemutatott példákat egy teszt szubrutin segítségével! Gépelje be a következő szubrutin keretet a kódszerkesztő ablakba, majd a kód felirat helyére másolja be az egyes vezérlőszerkezeteknél bemutatott példákat. Végül futtassa a (teszt) szubrutint az 1. leckében leírt módon! | |||||||||||||||
Sub teszt() | |||||||||||||||
Eljárás hívása | |||||||||||||||
[Call] name[argumentlist] | |||||||||||||||
| |||||||||||||||
Az eljárás hívásának kulcsszava (Call) elhagyható. Megadásakor az argumentumlistát zárójelbe kell tenni, ha elhagyjuk, akkor a zárójelet is el kell hagyni. | |||||||||||||||
Függvény hívása | |||||||||||||||
A függvények kifejezések részeként hívhatók (hasonlóan, mint a VB függvényei), azaz a függvényhívás bárhol állhat, ahol egy, a függvény eredményének megfelelő érték állhat (pl. egy értékadó utasítás jobb oldalán). Az aktuális paraméterek zárójelei nem hagyhatók el. | |||||||||||||||
Egy szubrutin hívásakor megtörténik az aktuális és formális paraméterek megfeleltetése (a paraméterek átadása), majd a végrehajtás a hívott szubrutin utasításaival folytatódik. A hívott szubrutin befejeztével a végrehajtás a hívást követő utasítással folytatódik. | |||||||||||||||
Hívás megnevezett paraméterekkel | |||||||||||||||
Ez a fajta szubrutinhívás kényelmes hívást biztosít olyan szubrutinok esetén, amelyeknek sok opcionális paramétere van. Elegendő csak azokat a paramétereket és aktuális értékeiket felsorolni, amelyeket át akarunk adni, a többinek meghagyjuk az alapértelmezett értékét. | |||||||||||||||
Pl. | |||||||||||||||
ActiveWorkbook.SaveAs FileName:="Mentes.xls" | |||||||||||||||
A példában egy objektum egy metódusát hívtuk meg, ami az aktív munkafüzetet menti el a megadott névvel. Az objektumokról és a metódusokról későbbi leckékben lesz szó. | |||||||||||||||
Megjegyzés | |||||||||||||||
| |||||||||||||||
Mintafeladat | |||||||||||||||
A szubrutinok deklarálását és hívását az alábbi feladat segítségével szemléltetjük. | |||||||||||||||
Fordítsunk meg egy adott sztringet! | |||||||||||||||
Az alábbiakban mind függvénnyel, mind eljárással megoldjuk a feladatot, és mindkét esetben egy hívó, tesztelő szubrutint is készítünk. Erre azért van szükség, mert a paraméterekkel rendelkező szubrutinok nem futtathatók közvetlenül, márpedig a megoldó függvénynek, illetve eljárásnak lesz paramétere. A paramétert a megfordítandó sztring átadására, az eljárással történő megoldás esetén még az eredmény visszaadására is használjuk. | |||||||||||||||
Az első megoldásban (Fordit függvény) a kezdetben üres eredménysztringhez (er) jobbról hozzáfűzzük a sztring karaktereit fordított sorrendben, azaz először a legutolsót, majd az utolsó előttit, legvégül az elsőt. Amikor az eredménysztring előállt, akkor a megfelelő értékadással (amikor is a függvény neve értéket kap) gondoskodunk az eredmény beállításáról. | |||||||||||||||
A második megoldásban (MegFordit eljárás) a kezdetben üres eredménysztringhez (er) balról hozzáfűzzük a sztring karaktereit eredeti sorrendben, aminek eredményeként a sztring első karaktere kerül az eredménysztring legvégére, a második karaktere lesz az utolsó előtti, végül az utolsó karaktere kerül az eredménysztring legelejére. | |||||||||||||||
Természetesen a megoldások lényegét adó ciklusok lehetnének egyformák is, de a kétfajta megközelítéssel azt szerettük volna érzékeltetni, hogy még egy ilyen egyszerű feladatnak is létezhet többféle megoldása. | |||||||||||||||
Megjegyzés: Olyan megoldás is elképzelhető, amelyben a sztring megfelelő karakterpárjait cserélgetjük fel. Az első karaktert az utolsóval kell kicserélni, a másodikat az utolsó előttivel, és így tovább. | |||||||||||||||
'Sztring megfordítása függvénnyel | |||||||||||||||
'A Fordit tesztjéhez ez indítandó | |||||||||||||||
'Sztring megfordítása eljárással | |||||||||||||||
'A MegFordit tesztjéhez ez indítandó | |||||||||||||||
A lecke lezárásaként megjegyezzük, hogy a VB nem engedi meg a szubrutinok egymáson belüli deklarálását, de a rekurziót (amikor is egy szubrutin önmagát hívja meg, vagy több szubrutin hívja egymást kölcsönösen) igen. A rekurzív algoritmusok iránt érdeklődőknek a szakirodalmat - pl. (Pusztai 2008) vagy (Cormen et al. 2003) - ajánljuk. | |||||||||||||||
Önálló programozási feladatok | |||||||||||||||
Készítsen Visual Basic szubrutinokat az alábbi feladatokra! A bemenő adatokat az InputBox függvénnyel kérje be, az eredményeket a MsgBox függvénnyel írja ki! Feltehető, hogy a felhasználó jó adatot ad meg! | |||||||||||||||
Pl. Kérjünk be egy egész számot és írjuk ki a négyzetét! | |||||||||||||||
Sub Negyzet() | |||||||||||||||
1. Kérjük be egy kör sugarát, majd írjuk ki a kör területét és kerületét! (Tipp: A bekérést, a számolást és a kiírást egymás után (szekvencia) hajtsuk végre!) | |||||||||||||||
2. Kérjünk be két egész számot, majd írjuk ki a nagyobbik szám értékét! (Tipp: A bekérés után a megfelelő eredmény kiírása szelekció segítségével történhet.) | |||||||||||||||
3. Adott három szám esetén mondjuk meg azt, hogy lehet-e a három szám egy síkbeli háromszög három oldalának a hossza vagy sem! (Tipp: Ha bármelyik két oldal hosszának összege nagyobb, mint a harmadik oldal hossza, akkor "lehet", egyébként "nem".) | |||||||||||||||
4. Adott két kör a síkon a középpontjának koordinátáival és a sugarával. Mondjuk meg azt, hogy van-e a köröknek közös pontja vagy sem! (Tipp: Ha a középpontok (Pitagorasz-tétellel kiszámolt) távolsága nagyobb, mint a két sugár összege, akkor "nincs", egyébként "van".) | |||||||||||||||
5. Oldjuk meg az ax2+bx+c=0 másodfokú egyenletet a valós számok körében, ahol az a, b és c együtthatók értékei valós számok! (Tipp: A feladat teljes megoldása kezeli az elsőfokú és a másodfokú eseteket (0, 1, illetve 2 db valós gyök) is!) | |||||||||||||||
6. Egy sztringben egy olyan név szerepel, amely két részből áll (családnév, keresztnév), a két részt pontosan egy szóköz választja el. Cseréljük fel a név két részét! (Tipp: Használjuk az InStr, Left és Right függvényeket!) | |||||||||||||||
Pl. "Makk Marci" | |||||||||||||||
7. Állítsunk elő adott karakterből álló, adott hosszúságú sztringet! (Tipp: Egy For ciklus segítségével egy kezdetben üres sztringhez fűzzük hozzá a megadott karaktert!) | |||||||||||||||
Pl. "*", 3 | |||||||||||||||
8. Soroljunk be egy adott, legalább két karakterből álló sztringet az alábbi 4 osztály valamelyikébe! Egy sztring | |||||||||||||||
| |||||||||||||||
(Tipp: Az első három esethez vegyünk fel egy-egy logikai változót és állítsuk őket igaz (True) kezdőértékre, majd egy ciklussal vizsgáljuk meg a sztring szomszédos karaktereit (először az elsőt és a másodikat, azután a másodikat és a harmadikat, ..., legvégül az utolsó előttit és az utolsót)! A vizsgálat állítsa hamisra (False) azokat a logikai változókat, amelyek nem teljesülnek (pl. ha a két karakter különböző, akkor a sztring jelei már nem lehetnek azonosak)! A ciklus befejeztével írjuk ki a besorolás eredményét a logikai változók értékei alapján (pl. ha a három logikai változó egyike sem igaz, akkor a sztring az "egyéb" kategóriába tartozik)! | |||||||||||||||
9. Adott n pozitív egész számra írjuk ki a Fibonacci-sorozat első n elemét! A képzés módszere: az első két elem értéke 1, ezután minden következő az előző kettő összege (Pl. n=6: 1, 1, 2, 3, 5, 8). (Tipp: Az n<=2 esetek külön kezelendők, egyébként meg használjunk három változót és egy ciklust a feladat megoldására!) | |||||||||||||||
10. Határozzuk meg két pozitív egész szám legkisebb közös többszörösét! (Tipp: Jelölje a kisebbik számot a, a másikat b. Vizsgáljuk a többszöröseit (a, 2*a, 3*a, ...) egészen addig, amíg b egy többszörösét nem kapjuk. Ilyen szám előbb utóbb lesz, ha más nem, akkor a*b. Egy c szám b többszöröse, ha b megvan benne maradék nélkül, azaz c Mod b=0.) | |||||||||||||||
11. Számítsuk ki két adott, egy napon belüli időpont között eltelt időt! Az időpont óra, perc, másodperc értékekkel adottak, az eredményt is így adjuk meg! (Tipp: Alakítsuk "napon belüli" másodperccé a két időpontot, vegyük ezek különbségét, majd alakítsuk óra, perc, másodperc alakra!) | |||||||||||||||
12. Döntsük el három egész számról azt, hogy Pitagoraszi számhármast alkotnak-e vagy sem! Ha a három szám éppen egy síkbeli, derékszögű háromszög három oldalának a hossza, akkor ilyen számokról van szó, egyébként nem. (Tipp: Ha valamelyik két oldal négyzetének összege éppen a harmadik oldal négyzetét adja, akkor "igen", egyébként "nem".) | |||||||||||||||
13. Adott két zárt intervallum a valós számegyenesen. Mondjuk meg, hogy van-e közös pontjuk vagy sem! (Tipp: Ha valamelyik intervallum bal széle bent van a másik intervallumban, akkor "van", egyébként "nincs".) | |||||||||||||||
14. Határozzuk meg az X és Y koordinátáját egy polárkoordinátákkal adott P(r, ) síkbeli pontnak! A szög fokban adott. (Tipp: A Sin és Cos függvények használatához előbb számoljuk át radiánba a fokban adott szöget!) | |||||||||||||||
15. Adott n és k pozitív egész számokra határozzuk meg a binomiális együttható értékét! (Tipp: A képletet (n!/(k!*(n-k)!)) ne a számláló és a nevező kiszámolása utáni osztással számoljuk ki (a nagy számok miatti pontatlanság/túlcsordulás miatt), hanem előbb egyszerűsítsük a képletet k!-sal, majd a kapott törtet bontsuk n-k db tört szorzatára, és ezt számoljuk ki!) |