A Pascal a struktúrált programozást erősen támogató nyelv. A struktúrált nyelvekben 3 féle vezérlési
szerkezet van.
1. szekvencia
2. szelekció
3. iteráció
Az elsőt már ismerjük. A szekvencia nem más mint amikor utasításokat adunk meg egymás után. Ilyenkor a
program végrehajtása az első soron kezdődik és halad sorban (szekvenciálisan). Ez nem valami nagy szám.
Nézzük meg a másodikat. Szelekció, azaz elágazás. Tegyük fel, az a feladat, hogy eldöntsük egy számról
kisebb-e mint 100. Íme a kód:
Program Elagazas; { Programunk neve. }
Uses crt; { Crt unit csatolása. }
var szam : Integer; { Változó deklarálása (létrehozása). }
BEGIN { Főprogram kezdete. }
ClrScr;
Write('Add meg a számot: ');
ReadLn(szam); { Bekérjük a számot. }
if (szam<100) then { Ha kisebb 100-nál akkor }
Write('Ez a szám kisebb mint 100.')
else { Különben }
write('Ez a szám nem kisebb mint 100.');
ReadKey;
END. { Főprogram vége. }
Az elágazást az "if (feltétel) then utasítás [else utasítás]" szerkezettel lehet megvalósítani. Az if
kulcsszót egy feltétel követi. Ha a feltétel igaz, akkor végrehajtja a then utáni utasítást. Itt csak egy
utasítás szerepelhet. Az else ág nem kötelező. Ha mégis van, akkor kerül ide a vezérlés, ha a feltétel nem
teljesül. Itt is egy utasítás állhat. Fontos megemlíteni, hogy az else előtti utasítás végén nem állhat ';'.
Úgy lehetne fordítani ezt, hogy: Ha (feltétel igaz) akkor utasítás_1 különben Utasítás_2;.
Mi a helyzet akkor, ha nem csak egy utasítást szeretnénk végrehajtani. Pl. legyen az a feladat, hogy miután
eldöntöttük kisebb-e mint 100 kiszámoljuk mennyivel kisebb és kiírjuk azt is. Ha nem kisebb, megmondjuk
mennyivel nagyobb.
Program Elagazas; { Programunk neve. }
Uses crt; { Crt unit csatolása. }
var szam : Integer; { Változó deklarálása (létrehozása). }
BEGIN { Főprogram kezdete. }
ClrScr;
Write('Add meg a számot: ');
ReadLn(szam);
if (szam<100) then
begin
WriteLn('Ez a szám kisebb mint 100.');
Write(100-szam,'-al kisebb 100-nál.');
end { Itt nincs ';'.}
else
begin
WriteLn('Ez a szám nem kisebb mint 100.');
Write(szam-100,'-al nagyobb 100-nál.');
end; { Itt viszont van ';'. }
ReadKey;
END. { Főprogram vége. }
Ha valamit begin end; közé teszünk, akkor az 1 utasításnak számít. Itt se felejtsük el, hogy az else elé
nem szabad ';'-t tenni. Viszont az else ágban az end után kellett a pontosvessző.
Van egy másik módszer is elágazások készítésére. Legyen most az a feladat, hogy beírunk egy számot és ha
kisebb mint 10 akkor kiiratjuk azt szöveggel.
Program elag_2;
Uses crt;
var szam : Integer;
BEGIN
ClrScr;
Write('Add meg a számot:');
ReadLn(szam);
case (szam) of
0 : write('Nulla');
1 : write('Egy');
2 : write('Kettő');
3 : write('Három');
4 : write('Négy');
5 : write('Öt');
6 : write('Hat');
7 : write('Hét');
8 : write('Nyolc');
9 : write('Kilenc'){ Ide sem kell pontosvessző, hiszen else következik. }
else write('Ezt a számot nem tudom kiírni betűkkel');
end; { A "case of"-ot egy end;-nek kell zárnia. }
ReadKey;
END.
A működése nagyon egyszerű. A case után megadott változó értéke ha megegyezik az alatta felsorolt
értékek egyikével végrehajta az utána álló utasítást. Itt is csak egy utasítás állhat, de mint az if-nél
lehetőség van a begin end; páros használatára. Az else ág itt sem kötelező, de ha van, akkor kerül ide a
vezérlés ha egyik értékkel sem talált megegyezést. Fontos megemlíteni, hogy a számok (a kettőspont előtt)
nem lehetnek változók. Csakis konstansok. Talán az is feltűnt, hogy mit keres ott az az end. Nincs hozzá
begin. Ez az end; a case-t zárja le.
Jöhet a harmadik, iteráció. Azaz ciklusok, más szóval valaminek az ismétlése. Ennek több módja is van.
Nézzük az elsőt! Legyen az a feladat, hogy megkérdezzük a felhasználót, hányszor szeretné látni a szöveget,
majd ki is írjuk annyiszor.
Program forciklus;
Uses crt;
var i : Integer; { Ciklusváltozó. }
meddig : Integer; { Hányszor szeretnék ismételni. }
BEGIN
ClrScr;
Write('Hányszor szeretnéd látni: ');
ReadLn(meddig);
for i:=1 to meddig do { Ismételd 1-től az előbb bekért számig. }
begin
WriteLn('Helló Világ!');
end;
ReadKey;
END.
A for ciklus egy előírt lépésszámú ciklus. Amint látható, használ egy változót, aminek a neve most i.
Ennek az i-nek a "for" után értékül adjuk az 1-et. A "to" után megadjuk meddig szeretnénk növelni i-t. Ez
volt a ciklus feje. Most következik a ciklus magja, vagyis amit ismételni fog. Jelen esetben a szöveg
kiírása. A Pascal minden egyes iteráció (azaz ismétlés) után növeli 'i' értékét 1-el. Az ismétlődés addig
tart amíg 'i' el nem éri a "to" után megadott értéket. Ha 'i'-t 1-ről indítjuk akkor pontosan annyiszor fog
ismételni, amennyit megadtunk a "to" után. Miután befejezte a ciklus a működését 'i'-értéke a "to" után
megadott értékkel lesz egyenlő.
Természetesen 'i'-t nem kötelező 1-ről indítani. Lehet akár 100-ról is. A "to" után pedig 105-öt adok meg.
Ez esetben hányszor fog lefutni?? Egy kis fejszámolás...... Remélem nem dőltél be!! Természetesen 6-szor.
Miért?? Mert a ciklus lefut 100-ra, 101-re, 102-re, 103-ra, 104-re, és 105-re. Ha ezt megszámolod, akkor
6db. Ugye az előbb 1-től indultunk. Most pedig 100-tól 105-ig vagyis, (ha kivonunk 100-at) 0-tól 5-ig. Íme
meg is van az eltérés oka. Ez a bizonos 0-tól kezdünk nem pedig 1-től "dolog" gyakran meg tudja zavarni a
kevésbé tapasztalt programozni tanulót. De te ne hagyd magad, figyelj rá oda!
Ha a "for" képes 'i'-t növelni, vajon csökkenteni tudja? Igen, tudja. Ekkor nem "to"-t kell írni, hanem
"downto"-t. Nyílván ekkor a dolgok megfordulnak, és az 'i' kezdőértékének kell nagyobbnak lenni. Ha nem
így van, akkor is elindul majd programunk, de nem fog lefutni a ciklusmag egyszer sem. Lássunk erre
is egy példát! Készítsünk el egy űrhajó kilövését időzítő programot, vagyis számoljunk 10-től vissza 0-ig!
Program _downto;
Uses crt;
var i : integer; { Ciklusváltozó. }
BEGIN
ClrScr;
for i:=10 downto 0 do
begin
WriteLn(i);
end;
ReadKey;
END.
Itt a kimenet a követező lesz:
10
9
8
7
6
5
4
3
2
1
0
Sajnos nem másodpercenként történik a kiírás, hanem olyan gyorsan amilyen gyorsan csak tudja a géped.
Valószínüleg csak annyit látsz, hogy miután elindult a program ott lettek a számok. De a "downto"-s ciklus
működik és most csak ez számít.
Most jöhet egy másik ciklusfajta, a feltételes ciklus. Ezt akkor használjuk, amikor nem tudjuk pontosan
hányszor szeretnénk ismételni valamit. Tegyük fel be akarunk kérni 10-től kisebb számot. Nem
tudhatjuk, hogy a felhasználó hányszor fog marhaságot beírni. Mindaddig ismételni kell, amíg hibás az
amit beírt. Feltételes ciklusból kettő is van a Pascalban. Van olyan ami elől tesztel és van olyan ami
hátul. Az előltesztelős ciklus magja lehet, hogy nem fut le egyszer sem. Ha a feltétel már az elején nem
teljesül, akkor be sem lép ciklusba. Ezzel ellentétben a hátultesztelős ciklus lefuttatja a magját egyszer,
majd csak utána ellenőrzi a feltétel teljesülését. Itt a ciklusmag 1-szer mindenféleképpen lefut. Nézzük
meg először az előltesztelőset!
Program _while;
Uses crt;
var szam : Integer;
BEGIN
ClrScr;
szam := 11; { Így teszem igazzá a while-ban megadott feltételt. }
while (szam >= 10 ) do { Ismételd, ha a feltétel igaz. }
begin { Ciklus magja. }
Write('Adj meg egy 10-től kisebb számot: ');
ReadLn(szam);
end;
END.
A "while" kulcsszó után itt is (hasonlóan az "if"-hez) egy feltételt kell megfogalmazni. A ciklus mindaddíg
ismétlődik amíg a feltétel igaz! A szam változó értéke a létrehozása után automatikusan nulla lesz. (A C-vel
ellentétben a Pascal ad kezdőértéket a változóknak.) A nulla ugye kisebb 10-től, így a feltétel nem
teljesülne és nem futna le egyszer sem a ciklusmag, nem kérnénk be egy számot sem a felhasználótól. Ezért
atdam értékül neki 11-et. Látszik, hogy a for ciklussal ellentétben itt nem változik automatikusan semminek
sem az értéke. A for ciklus előbb utóbb véget fog érni. A while nem biztos. Könnyen lehet olyan feltételt
kitalálni ami mindíg teljesül. Ezeket a ciklusokat hívják végtelen ciklusoknak. Végtelen ciklusból is több
féle létezik, nem térek most ki erre. Gondolom mondanom sem kell, hogy ha egy program sosem ér véget, akkor
az rossz. Figyelj oda rá, hogy ez ne forduljon elő. A "for"-ral ellentétben a while ciklus befejezéséről
gondoskodni programozó feladata.
Említettem egy másik feltételes ciklust, a hátultesztelőset. Írjuk meg ugyanezt a programot most ezzel.
Program _repeat;
Uses crt;
var szam : Integer;
BEGIN
ClrScr;
repeat { Ismételd... }
Write('Adj meg egy 10-től kisebb számot: ');
ReadLn(szam);
Until (szam < 10); { mindaddig amíg a feltétel hamis. }
END.
A ciklust a repeat (foglalt szó) vezeti be, de itt a feltétel a ciklus magja után van. Másik fontos
eltérés, hogy itt a ciklus addig ismétlődik, amíg a feltétel hamis. Mivel a ciklus magja egyszer mindenképp
lefut, fölösleges a szam változónak értéket adni. Az első vizsgálat úgyis csak azután történik, miután már
a felhasználó adott neki értéket. A két program működését tekintve teljesen megegyezik. Látható, hogy a két
ciklusfajta számos esetben felcserélhető. De akkor melyiket használjuk? Mindíg azt, amelyik jobban
illeszkedik az adott feladathoz. Jelen esetben most a repeat-el megspóroltunk egy értékadást, ezért ez
jobbnak tűnik. Talán azt is észrevetted, hogy most nem használtunk begin end; párost a ciklusmag
megadásánál. Nem is kell, hiszen a mag mindíg a repeat until szavak közé kerül, így pontosan tudja a
Pascal, mettől meddig tart az.
Ezzel meg is tárgyaltuk mindhárom vezérlési szerkezetet, mégegyszer, mik is voltak azok? Szekvencia,
szelekció, iteráció. A Pascalban elégazásokat és ciklusokat nem csak egymás után lehet használni. Azokat
egymásba is lehet ágyazni. Lehet olyat csinálni, hogy egy for-ban van egy if, azon belül egy while stb...
Így meglehetősen bonyolult kód készíthető. Fontos, hogy ne féljünk ezektől. Amikor látsz egy kódot, próbáld
meg azt fejben futtatni, (de vigyázz a végtelen ciklusokkal, nehogy éhen halj!!). Sok gyakorlás után már
nem is fog olyan nehéznek tűnni. Itt fontos a sok szót kiemelnem. Ha ez nehezedre esik, vagy csak egyszerűen
nincs hozzá kedved, akkor csak egy megoldás van. Ne foglalkozz programozással, ugyanis nem neked való! Ezt
most nem viccből mondtam. Sajnos tele van az egyetem olyan emberekkel akik saját bevallásuk szerint sem
szeretnek ilyenekkel bajlódni. A programozást egyfajta kényszernek tartják amit az iskola talált ki pusztán
azért, hogy őket szivassák. Szóval, ha úgy érzed nincs kedved a sok tanuláshoz, gyakorláshoz, nincs kedved
sokszor napokig agyalni valami elvont kézzel megfoghatatlan baromságon, akkor a programozás nem neked
való. Ez persze nem baj, biztosan találsz valami mást ami tetszeni fog. De érdemes már az elején tisztázni,
programozni megtanulni nem könnyű, sőt nagyon is nehéz.
Ha még nem vettem volna el a kedved és úgy döntesz folytatod, akkor elárulok egy titkot. Nem is annyira
titok ez, hanem inkább tabu a programozók közt. Létezik egy negyedik vezérlési szerkezet is. A feltétel
nélküli ugrás. Ez azonban egy "gonosz" szerkezet! Annyira képes megbonyolítani a kódot, hogy azt a
készítőjén kívül nem érti meg senki. Nagyobb programokat már nem egy ember készít, hanem 10,20, sőt akár
több száz emberből álló csapat. Olyankor létszükség, hogy a másik is értse mit csánál az ember programja.
Ezért van az, hogy a programozók nem használják ezt az eszközt. Egyébként matematikusok bizonyították,
mindent amit meg lehet csinálni a 4 vezérlési szerkezettel (azaz feltétel nélküli ugrást is használva),
azt meg lehet csinálni 3-al is (azaz a feltétel nélküli ugrás nélkül). Így ez feleslegessé vált. Ennek
ellenére néha még ma is fel-fel merül. Ugyanis a nyelvekből nem vették ki. A Pascalban is megtalálható.
Ezért írtam az elején, hogy a Pascal támogatja a struktúrált programozást. Lehet benne struktúrálatlanul is
programozni. Lássunk erre is egy példát!
Program _goto;
Uses crt;
var i : Integer;
label ide_ugorj;
BEGIN
ClrScr;
for i:=1 to 10 do
begin
WriteLn('Ez még az első ciklus.');
if (i=3) then
begin
goto ide_ugorj;
end;
end;
for i:=6 to 10 do
begin
WriteLn('Ez már a második ciklus.');
if (i>1000) then
begin
ide_ugorj: WriteLn('i értéke nagyobb mint 1000.');
end;
end;
ReadKey;
END.
Íme a kimente:
Ez még az első ciklus.
Ez még az első ciklus.
Ez még az első ciklus.
i értéke nagyobb mint 1000.
Ez már a második ciklus.
Ez már a második ciklus.
Ez már a második ciklus.
Ez már a második ciklus.
Ez már a második ciklus.
Ez már a második ciklus.
Ez már a második ciklus.
Hogy is van akkor ez? Maga a feltétel nélküli ugrás a goto (XY nélkül!!). Ahhoz hogy ukorjunk meg kell
mondani azt is, hogy hova. Erre valóak a címkék. Most egy ilyen cimke (label) van aminek az a neve, hogy
ide_ugorj. Miután a program elején létrehoztuk, bármelyik sor elé odatehetjük, felcimkézve azt. A goto
utasítás kiadásakor meg kell adni melyik cimkére szertnénk ugrani.
Talán furcsáljuk a kimenetet. Az első ciklusnak 10-szer kellett volna lefutni, e helyett csak 3-szor futott.
Ez érthető, hiszen amikor i elérte a 3-at beléptünk az if-be és ugrottunk. Méghozzá pont arra a sorra ami
kiírja nekünk az "i értéke nagyobb mint 1000." szöveget, nem törődve azzal, hogy egy olyan feltételben van
ami sohasem teljesülhet. Ráadásul a második ciklusnak csak 5-ször kellett volna futnia, helyette lefutott
7.5-szer, viszont csak 7-szer írta ki az "Ez már a második ciklus." szöveget. Miért? A goto-val sikeresen
beugrottunk egy ciklus közepébe. Így a fejben az i változó 6-ra állítása nem történik meg, továbbra is
marad 3. Az első Write után ugrottunk, így az sem hajtódik végre, megtévesztően csak 7-szer lesz kiírva
a szöveg, holott a ciklus magja hét és félszer futott le. Na pont az ilyen ocsmányságok elkerülése miatt
nem használja szinte senki sem a goto-t.
De akkor miért van benne? Mint említettem minden goto-s programot meg lehet írni goto nélkül is. Vannak
viszont olyan feladatok amikor sokkal gyorsabb programot lehet írni goto-val, mint nélküle.
A következő leckében megismerkedünk a logikai műveletekkel, igazságtáblákkal, precedenciával. Ha valamit nem
értettél, zavarosnak találsz, írd meg a fórumba.