Köszöntelek, kedves programozni vágyó!

Ide szabvány szerint egy szöveg kerülne, ami ecseteli, miért is lesz jó neked a programozás, de mivel belefogtál ennek a dokumentumnak az olvasásába, feltételezem, hogy már van valamiféle elképzelésed erről :)

A segédlet célközönsége mindazok, akik valamiféle probléma megoldása során hasznát tudnák venni a programozásnak, de nem tudják, hogyan fogjanak neki. Az anyag törekszik egyszerre helyes programozási szemléletet, valamint azonnal hasznosítható tudást is átadni, bár ez a két cél sajnos nem ellentmondásmentes.

Némi alapozás után párhuzamosan fogunk haladni az általános programozási módszerekkel, és ezek konkrét megvalósításaival egy remekül hasznosítható programozási nyelven. Mézesmadzagként nézzük, mire leszünk képesek:

Vágjunk is bele a témába!

1. Mi a programozás?

A programozás egy folyamat, ami a feladat megfogalmazásával kezdődik, majd a megoldás lépéseinek fokozatos kidolgozásával és finomításával folytatódik, s a gyakorlati megvalósítással ér véget (sőt, van hogy még ott sem).

Ebből a megfogalmazásból is kitűnik, hogy a programozás főképp jelentős mennyiségű tervezésből áll, maga a kódolás, azaz a "gépbe való bepötyögés", csak a folyamat végső szakasza. Ideális esetben egy helyesen végigvitt tervezés után a kódolás már nem intuitív feladat, inkább a kidolgozott megoldás átültetése. Persze a gyakorlatban a Dolgok sokszor távol esnek az ideálistól.

Haladjunk most visszafelé, és nézzük meg, milyen tudásra is lesz szükségünk az egyes szakaszokban!

A kódoláshoz ismernünk kell legalább egy programozási nyelvet. Miért is? Egyszerűen mondva, a számítógép nullákat és egyeseket ért meg, mi pedig az emberi nyelvet - ez a kettő pedig távol áll egymástól. A programozási nyelv egy kompromisszum, ami megragadt valahol a két nyelv közt (nyelve válogatja, hol), és közvetít.

Léteznek speciális és általános programozási nyelvek. Előbbiekre jellemző, hogy egy bizonyos feladatkört könnyű és gyors megfogalmazni és megoldani, az összes többit viszont nehézkesebb, vagy akár lehetetlen. Nekünk most az utóbbi, általános célú programozási nyelvre lesz szükségünk, a továbbiakban őket értjük programnyelv alatt.

Szerencsére a programnyelvek jellemzően mind a módszerek egy nagy közös kádjából merítenek, csak a tálalásuk más és más (persze ennél azért többről van szó, különben nem lenne szükség különféle általános programnyelvekre). Meg kell tehát ismernünk ezeket a közös módszereket! A jó programozó a kódolási szakasz előtt végig az általános módszertanban gondolkozik, nem egy konkrét programnyelvben (a jártas programozó pedig észben tartja a majdani lehetséges programnyelv sajátosságait, és ezekhez igazodva gondolkodik az általános módszertanban :).

A legnehezebb szakasz a magas szintű terv elkészítése. Itt kell a természetes nyelvű feladatkiírásból kihámozni, mit is kell csinálnunk, és a megoldásra egy tervet adnunk. A jó terv készítése nehéz. A jó tervet elolvasva világosan átlátjuk a megoldás menetét; egyes lépései maguk is lehetnek összetettek, amik további kifejtésre szorulnak; nem részletes annyira, hogy a konkrét megvalósítással foglalkozzon, mégis úgy érezzük, az egyes lépéseket nem lesz gond megvalósítani. Például a "Rendezzük növekvő sorrendbe a számokat" egy végtelenül egyszerű terv, mindenki érti, miről is van szó, a megvalósításról mégsem mond semmit.

A tervkészítésnél saját kreativitásunkra lesz szükségünk, és sok tapasztalatra, hogy mit hogyan érdemes tenni. A tapasztalat megszerzésében a példák, a gyakorlás és a kérdezés fog segíteni.

2. Az algoritmus és a pszeudo-kód

Az algoritmus szó a megoldás menetét jelenti, egy réges régen élt Közel-keleti tudós könyvének a címéből származik, amiben olyanokat írt le, mint például a papíron való összeadás menete, satöbbi. Az algoritmus szót használhatjuk a magas szintű tervre, és az egész részletesen kifejtett megvalósítási tervre is.

Például a teakészítés algoritmusa:

Az algoritmust sokféleképp jegyezhetjük le. A teakészítésnél használt módszer egy recept-szerű, természetes nyelvű leírás volt. Más lehetséges módszer például a folyamatábra vagy a pzseudo-kód. Mi az utóbbit fogjuk használni. A pszeudo-kód onnan kapta nevét, hogy szerkezetében hasonlít a programozási nyelvekre, mégsem követel meg aprólékos precizitást, így kényelmesen fogalmazhatjuk meg mondanivalónkat. Valahol a természetes emberi nyelv, és a programnyelvek közt helyezkedik el. Elsősorban a pszeudo-kódon keresztül fogunk megismerkedi azzal, mire is lehet rávenni egy számítógépet.

3. Mire vehetjük rá a számítógépet?

Alapvetően arra, hogy adatokat tároljon, és ezeken az adatokon műveleteket (utasításokat) hajtson végre.

Az adatok lehetnek változók (variables), illetve konstansok (például fizikai konstansok értékei). Így is hívjuk őket. Az adatnak típusa van, például logikai (igaz-hamis), szám, vagy szöveg.

A továbbiakban a változókról fogunk beszélni, de nyilván a konstansok is hasonlóan viselkednek, kivéve, hogy értékük nem változhat meg.

3.1 Változók

A változók a számítógép memóriájában helyezkednek el, egyelőre képzeljük úgy el, hogy minden változó egy-egy memóriarekeszben helyezkedik el. Ezeknek a rekeszeknek címe van, akár a házaknak az utcában - csak jóval több számjegyű. Valahogy meg kell tudnunk mondani, hogy egy adott műveletben melyik változót szeretnénk használni; hivatkozhatnánk rájuk a címükkel, de ez nagyon nehézkes lenne ("Anya, átugrom a 17834252-es házba"). Ehelyett a változókhoz nevet rendelünk ("Anya, átugrom a Pistihez").

Az alap változó-típusokhoz tartozó szokásos műveletek megtalálhatóak, mint például számoknál az alapműveletek, szövegnél a szövegek összefűzése, logikai értékeknél a Boole-műveletek (és, vagy stb). Később mi is fogunk saját műveleteket (függvényeket) bevezetni, hogy megkönnyítsük az életünket.

Írjunk egy egyszerű algoritmust eddigi eszköztárunk segítségével. A változók neveivel kapcsolatban:

Íme az algoritmus:

beolvas szám
// Ez itt egy megjegyzés, "komment"
másik_szám := 5
// := ("legyenen egyenlő") az értékadás jelölése
eredmény := szám * másik_szám
// A p-kód megengedi, hogy elvont utasításokat írjunk, mint a kiír
kiír eredmény

Ebben a pszeudo-kód részletben nem írtuk le külön, hogy mik a változók. Hallgatólagosan a józan emberi értelmezésre bíztuk ennek feloldását. Ilyen egyszerűbb esetben ez elfogadható, máskor azonban hasznos lehet a változóneveket típusukkal együtt felsorolni, például:

szám1, szám2, másik_szám : egész_szám
név : szöveges
beolvas név
...

3.2 Vezérlési szerkezetek

Valóban, jelenlegi eszköztárunkkal igen szegényes algorutmusokat tudunk csak írni. Eddig a számítógépet csak az utasításaink sorban történő végrehajtására tudtuk rávenni. Ez az alapértelmezett, szekvenciális végrehajtás.

A vezérlési szerkezetekkel az utasítások végrehajtásának módját tudjuk szabályozni. A szekvencián kívül még két alapvető vezérlési szerkezet van: a feltételes elágazás és a ciklus.

3.2.1 A feltételes elágazás

A feltételes elágazással egy feltétel teljesülésétől függően hajtunk végre egy kódrészletet. Formája az alábbi:

Ha <feltétel>
akkor
	utasítás-blokk
e.v.

Az e.v. az "elágazás végének" a rövidítése. Ha a megadott feltétel igaz, akkor az "akkor" és "e.v." közti rész végrehajtódik, különben egyszerűen kimarad. A feltétel nem más, mint egy logikai kifejezás. Ez lehet egy logikai típusú változó, vagy mondjuk egy változók közt értelmezett reláció eredménye.

Példaképp az alábbi programocska beolvas két számot, majd ha az összegük nagyobb tíznél, azt tudatja velünk.

szam1, szam2 : egész_szám

beolvas szám1, szám2
Ha szám1 + szám2 > 10
akkor
	kiír "Az összeg nagyobb tíznél"
e.v

Nézzük a feltételes elágazás egy másik formáját!

Ha <feltétel>
akkor
	utasítás-blokk
különben
	utasítás-blokk
e.v.

Ebben az esetben a feltétel teljesülése esetén az első, különben pedig a második utasítás-blokk fog végrehajtódni.

Végül nézzük meg, hogy kezelhetjük azt az esetet, amikor nem kettő, hanem több eset megkülönböztetésére van szükségünk:

Ha <feltétel_1>
akkor
	utasítás-blokk
különben ha <feltétel_2>
	utasítás-blokk
különben ha <feltétel_n>
	utasítás-blokk
különben
	utasítás-blokk
e.v.

Természetesen az utolsó, "egyéb" eseteket lekezelő különben ág elhagyható. Az alábbi program tudatja velünk két szám viszonyát:

szám1, szám2 : egész_szám

beolvas szám1, szám2
Ha szám1 < szám2
akkor
	kiír "Második nagyobb"
különben ha szám1 > szám2
akkor
	kiír "Első nagyobb"
különben
	kiír "Egyenlőek"
e.v.

3.2.2 A ciklus

Ciklusból többféle van, de ez inkább kényelmi szempont. Most az elöltesztelős ciklussal ismerkedünk meg, később majd találkozunk a többiekkel is. Az elöltesztelős ciklus kicsit hasonlít a legelső fajta feltételes elágazásra, de az utásításblokkját (amit ciklus esetében ciklusmagnak hívunk) addig ismétli, amíg a megadott feltétel (ciklusosan szólva: ciklusfeltétel) igaz. Nevét onnan kapta, hogy még a ciklusmagba lépés előtt "teszteli" a ciklusfeltételt, így ha az eleve hamis, akkor egyszer sem hajta végre a ciklusmagot. Ha viszont belelépett a ciklusmagba, ott is marad, amíg a feltétel igaz marad. A feltétel-vizsgálatot a ciklusmag minden egyes végrehajtása után végzi el, tehát "menet közben" nem lép ki belőle.

Ciklus amíg <cilusfeltétel>
	ciklusmag
c.v.

A c.v. jelentését mindenki találja ki maga, ha megvan, akkor haladjunk tovább első ciklusos példánkra:

i, meddig, összeg : egész_szám

beolvas meddig
összeg := 0
i := 1

Ciklus amíg i <= meddig
	összeg := összeg + i
	i := i + 1
c.v.

kiír "A sorösszeg: ", összeg

A fenti példa összeadja a számokat 1-től a beolvasott számig. Ciklusokban gyakran használunk futó változót, mint itt az "i" változó, ezek általában egy tartományon futnak végig. Hagyományosan i,j,k, esetleg m,n,l betűket használunk jelölésükre (persze nem tilos mást használni).

3.2.3 A feltételekről

Van egy-két fontos tudnivaló a feltételek alkalmazásával kapcsolatban, főleg, hogy nemsokára kipróbáljuk eddigi tudásunkat gyakorlatban is.

A feltételünk gyakran többmindentől függ. A többminden több rész-kifejezést jelent, ezeket a szokásos logikai műveletekkel kapcsoljuk össze. Például:

Ez ugye elég egyszerű, de a műveleti jelek (operátorok) közti erőviszonyra figyelni kell. Legerősebb a negálás, majd az ÉS, végül a VAGY művelet következik. Ehhez még hozzájönnek más operátorok is, amiknek már nehézkes fejben tartani az erősségét. Ilyenkor legjobb, ha zárójelezünk. (alternatíva: a programozási nyelv referenciájában megkeressük az "operator precedence" részt)

A zárójelezés mellett szól az is, hogy egyes programozási nyelvek például a nulla értékű változókat logikai hamisnak, a nem-nulla értékűeket igaznak tekintik (és fordítva: igaz => 1, hamis => 0, így például értelmes lehet az "(a ÉS b) < c" kifejezés is (persze ez nagyon nagyon csúnya).

c : logikai
a, b, d : szám
...

x := a <= b vagy nem c és d < b		// átláthatatlan valami, lehet hogy nem is helyes
x := (a <= b) vagy ((nem c) és (d < b))	// így már jobb

A konkrét programozási nyelvek eltérően jelölhetik a műveleti jeleket. Például a Pascal nyelv a már ismert := jelet használja értékadásra, és az = jelet összehasonlításra. Ezzel szemben C-ben vagy Pythonban az = jel való értékadásra, és az == jel összehasonlításra.

Például C-ben az "a = 1" kifejezés mindig igaz, mivel az = nem összehasonlít, hanem értékül adja az 1-et az "a" változónak, és ráadásul a nem-nulla szám az igaz, így az egész igaz. Ez gyakori hiba, amit az emberi szem nehezen vesz észre, ezért ebből tanulva a Python nyelv nem engedi meg feltételben az értékadást. (Itt felmerül az emberben, hogy egyáltalán miért akarhat valaki feltételben értékül adni akármit is.. ez általában elkerülhető lenne, de a lustaság nagy úr)

Végül szót kell ejteni a feltétel szigorú kiértékeléséről. A szigorú kiértékelés azt jelenti, hogy kiértékelődik a teljes kifejezés akkor is, ha már egy részéből tudni lehet a végkimenetelt. Ezzel ellentétben a nem-szigorú kiértékelés leáll, ha már egy rész alapján eldöntötte a végeredményt.

Ez akkor fontos, hogyha a logikai értéket szolgáltató függvényünk olyan, hogy meg is változtat valamit (pl. egy változót). Egy példán érthetővé válik a dolog:

// Nem érdekes, hogy hogyan lehet erre képes, de legyen
// a valami(x) függvény olyan, hogy igazat ad vissza,
// és a paraméterét megnöveli eggyel

a : szám
b : logikai

a = 0
b = Igaz
Ha b vagy valami(a)
akkor
	...
e.v

kiír a

A feltétel kiértékelése balról jobbra történik. Mivel "b" igaz, a vagy-kapcsolat biztos, hogy igaz lesz. Tehát a feltételt nem kell végig kiértékelni.

A különbség ott van, hogy szigorú kiértékelés esetén "a" értéke megnő, míg nem-szigorú esetben nem. Tehát ha arra számítunk, hogy "a" értéke mindig meg fog nőni, de a programnyelv nem-szigorú kiértékelése miatt ez nem igaz, csúnya meglepetések érhetnek minket. Mindig tájékozódjunk efelől! A C és Python nyelvek feltétel-kiértékelése nem szigorú.

Összefoglalva mire kell figyelni:

3.3 Kedvcsináló a Python nyelvvel

Most röviden megismerkedünk a Python programozási nyelvvel, szélviharszerűen feltelepítjük a Python-értelmezőt, és kipróbáljuk rajta, amit eddig megismertünk.

3.3.1 A Python nyelvről

3.3.2 A Python telepítése

3.3.3 Gyakorlatozás Pythonnal