Programozás
Verzió: 1.0
Perényi Zsigmond
2000. február 28.
1. Bevezetés
1.1 A hardver és a szoftver jelentőségének változása
| A számítástechnika hajnalában (1950-es évek) a hardvernek sokkal nagyobb
volt a jelentősége, hiszen akkoriban magának a számítógépnek, mint szerkezetnek
az öszzeállítása és működtetése jelentette a legnagyobb problémát. Akkoriban
csak a hozzáértő szakemberek jutottak számítógép közelébe, így nem is volt
cél, hogy kimondottan felhasználóbarát programokat írjanak. |
|
Ahogy a technológia fejlődött, úgy a számítógép (a hardver) egyre megbízhatóbbá
és olcsóbbá vált, így fokozatosan eljutott a kisebb cégekhez, s mára a
hétköznapi emberig. Tehát a felhaszánlók köre megváltozott: profi szakemberek
helyett most gyermekek, tanárok, orvosok, titkárnők, pékek, és takarítónők
ülnek a gépek előtt, és minden joggal elvárják, hogy a számítógépet a saját
különböző céljaikra a lehető legkényelmesebben lehessen felhasználni, a
legkevesebb tanulással.
De mivel a számítógép hardvere csupán egy halom vas és műanyag, ami
önmagától semmi értelmes dologra nem képes, a fent említett hatalmas felhasználói
igényeket a programoknak (szoftvereknek) kell biztosítani. A számítástechnika
története során tehát a hangsúly áthelyeződött a hardverről a szoftverre.
Mára a szoftvergyártás (vagyis a programozás) jelentős iparággá nőtt.
1.2 A hardver és a szoftver kapcsolata: a számítógépek
működése
1.2.1 Számítógépek
A számítástechnika fejlődése során számtalan különböző próbálkozás született
arra, hogy miként lehetne a számításokat valamilyen géppel elvégeztetni.
Mindközűl a Neumann-elvű gépek bizonyultak a legsikeresebbnek, a
modern elektronika pedig megteremtette a digitális technológia alkalmazásának
műszaki feltételeit.
A Neumann-elvű számítógépek lényege, hogy mind az adatok, mind az elvégzendő
feladat (kódolt utasítások formájában) a memóriában van eltárolva. A digitális
szó azt jelenti, hogy mindent számokként ábrázolunk, és azokat dolgozzuk
fel.
A ma körülöttünk lévő számítógépek mind ilyen elven működnek, legyen
az PC, Macintosh, nagygép, laptop, palmtop, vagy akár mobiltelefon, CD
játszó, vagy mikrohullámú sütő processzora. Ezért ettől a ponttól számítógépen
Neumann-elvű digitális számítógépet értünk.
1.2.2 A programvégrehajtás menete
-
A memória
-
minden rekesze sorszámmal (címmel) rendelkezik, így a memória bármely rekesze
megcímezhető, és így a processzor által közvetlenül elérhető.
-
A CPU (központi feldolgozó és vezérlő egység, a ,,processzor'')
-
feladata, hogy végighaladjon a program utasításain, és az előírt sorrendben
végrehajtsa azokat. Az utasítások műveleteket végeznek az adatokon.
|
-
a soron következő utasítás gépi kódja lehívódik a memórióból a CPU-ba
-
dekódolás: megállapítja, hogy milyen adatokkal milyen műveletet kell elvégezni
-
beolvassa a memóriából a szükséges adatokat, végrehajtja az előírt utasítást,
az eredményt pedig visszaírja a memóriába
|
1.3 A programozás alapjai
1.3.1 A gépi kód
A memóriában az utasítások kódolva tárolódnak, az adott processzor ,,nyelvén''
(a különböző processzoroknak különböző utasításai vannak. Utasítás alatt
itt egyszerű, elemi utasítást kell érteni, pl. 2 szám összeadása, szorzása,
egy szám másolása egyik memóriarekeszből a másikba... ). Minden utasításnak
van egy kódja (ez lényegében egy szám). Az adott utasításhoz meg kell adni,
hogy milyen adatokkal számol, pl. az általa használt adatok memóriacímét
(azt a sorszámot, amely memória rekeszben elhelyezkedik). Így lehet a programot
számokkal kódolni. Az így kapott kód a gépi kód. A programozás tehát lényegében
ennek a gépi kódnak a megalkotása.
1.3.2 Programozási nyelvek, fordító/értelmező
Ez természetesen nagy odafigyelést igénylő, fáradtságos munka, amit nehéz
megtanulni, könnyű elhibázni. Ezért már korán rájöttek, hogy a programozó
munkáját minél jobban meg kell könnyíteni. Ennek érdekében programozási
nyelveket dolgoztak ki, hogy ne számokkal kelljen programozni, hanem
sokkal emberközelibb módon, olyan nyelven, amelyben számok (kódok
és címek) helyett angol szavak szerepelnek. Egy ilyen nyelvet azonban nem
,,ért meg'' a gép, ezért ezt le kell fordítani a gép nyelvére. Ehhez
szükség van egy olyan segédprogramra, amely az általunk megírt programot
gépi kóddá alakítja (ez a fordító, compiler), vagy lépésenként végrehajtja
(ez az értelmező, interpreter).
|
fordító (compiler) |
értelmező (interpreter) |
| jellemzője |
a program forrásszövegéből egy gépi kódú, futtatható programot (pl.
EXE) állít elő, vagyis a programot lefordítja a gép nyelvére |
a program forrásszövegét sorról sorra értelmezi, ellenőrzi,
és (ha tudja) végrehajtja |
| szintaktikai (alaki) hibák kiszűrése |
fordítási időben (+) |
futási időben (-) |
| az elkészült program végrehajtási sebessége |
gyorsabb (+) |
lassabb (-) |
| a program hordozhatósága |
rosszabb (-) |
jobb (+) |
| a fejlesztés körülményessége |
nehézkesebb (-) |
egyszerűbb (+) |
1.3.3 Programozási hibák, hibakeresés
Természetesen egy magas szintű nyelven írt program írása közben is véthetünk
hibákat. Ez lehet:
-
szintaktikai hiba (alaki): a program nem felel meg az adott nyelv
szabályainak. Pl. elírás, elfelejtettünk egy zárójelet... Az ilyen hibákat
viszonylag könnyű megtalálni.
-
szemantikai hiba (tartalmi): a program lefordul, elindul, de nem
azt csinálja, amit kell, esetleg menet közben le is áll a hiba miatt. Az
ilyen hibák sok gondot okoznak, s poloska módjára búvnak meg a programban,
ezért ezeket a hibákat a poloska angol megfelelője után bug-nak
nevezik. Az ilyen hibák megtalálása és kiírtása (debuggolás)sokkal
nehezebb feladat, erre külön segédprogramok (debugger-ek) állnak
rendelkezésünkre.
1.4 A programozás módszereinek változása
A számítástechnika története során a programok készítésének módszerei és
eszközei is fejlődtek - könnyebbé váltak.
A főbb állomások:
-
gépi kód
az adott gép processzorának ,,nyelvén'' : számok (utasítás- és operandus
kódok) sorozata
-
assembly nyelv
a gépi kód emberibb változata, ahol minden gépi kódú utasításnak egy
kis angol neve van
-
magas szintű nyelvek (pl. PASCAL, C, C++, Java)
könnyű bennük ismétlési és döntési szerkezeteket, valamint alprogramokat
készíteni
-
integrált fejlesztő eszközök
olyan programfejlesztő környezetek, amelyek megkönnyítik a programozásnál
megszokott szerkesztés-fordítás-hibakeresés munkaciklust: a szövegszerkesztő
(editor), fordító (compiler), és hibakereső (debugger) egy helyen találhatók
és jól együttműködnek.
-
vizuális fejlesztőeszközök
olyan integrált programfejlesztő környezetek, melyekben sok programozói
feladat szinte néhány egérkattintásra egyszerűsödök: pl. megrajzoljuk a
leendő program dialógus ablakjainak elemeit, a fejlesztő eszköz pedig automatikusan
-
legenerálja a megfelelő kódot: (vagyis megírja helyettünk a program egy
részét)
-
dokumentációt készít...
1.5 Programozási nyelvek
1.5.1 Csoportosításuk, jellemzésük
A számítástechnikában használatos nyelveket a nyelv által megoldandó probléma
alapján 2 nagy csoportra oszthatjuk:
-
leíró jellegű nyelvek
egy állandó állapotot (tényeket) fogalmazhatunk meg bennük, nem pedig
cselekvést. pl. HTML, VRML
-
(procedurális) programnyelvek
algoritmikus cselekvést (tennivalók sorozatát) fogalmazunk meg bennük.
Ilyen elven működnek a Neumann elvű számítógépek. Innentől nyelven elsősorban
ilyen programnyelvet értünk.
A nyelv absztrakciós szintje alapján:
alacsony szintű nyelvek
nehezebb a programírás, de a lefordítandó program közelebb áll az gép
nyelvéhez (a gépi kódhoz), így nehezen hordozható (más típusú gépekre),
viszont több beleszólásunk van a gépközeli dolgokba… pl. assembly
magas szintű nyelvek
könnyebb programot írni (pontosabban egy emberközeli probléma megfogalmazása
könnyebb). A nyelv által nyújtott kényelm és az gép utasításkészlete közötti
űrt a fordító/értelmező programnak kell áthidalnia. pl. Java
1.5.2 A fontosabb programnyelvek
A ma is élő, legelterjedtebb általános nyelvek:
-
assembly
-
gépi kódú programozást segítő nyelv
-
a megírt program nehezen horozható
-
ma már csak az operációs rendszerek készítői, ill. a hardvergyártók programoznak
ilyenben
-
PASCAL
-
eredetileg a struktúrált programozás tanulónyelvének szánták
-
továbbfejlesztett változata, a TURBO PASCAL a modulok, illetve ma már az
OOP-t is támogatja
-
a valós életben a C miatt nem tudott érvényesülni, illetve a DELPHI-ben
él tovább
-
DELPHI
-
alapja az objektum-orientált Turbo Pascal
-
fő erőssége a korszerű és hatékony vizuális fejlesztőfelület
-
fő korlátja, hogy egy céghez (Borland), és egy platformhoz (Windows) kötődik
-
C
-
alacsony és magas szintű nyelvként is szokták emlegetni, mert hatékony
is, könnyű is programozni…
-
minden (fontos) géptípusra van C fordító -> (viszonylag) hordozható nyelv
-
régen minden általánosat C-ben írtak, ma a helyét egyre jobban átveszi
a C++. Ahol megmarad, az a
-
rendszerprogramozás
-
C++
-
a C nyelv objektum-orientált továbbfejlesztése
-
ma már a legtöbb géptípusra van C++ fordító is -> elég hordozható nyelv
-
napjainkban minden (általános) programot ebben írnak
-
Java
-
egy képzeletbeli (virtuális) Java-gép programnyelve
-
szintaktikája nagyon hasonlít a C++ -éhoz
-
a nyelv szabványos részét képezik a leggyakrabban kellő alapkönyvtárak,
mint pl. a grafika, felhasználói felület, hálózat programozás, adatbáziskezelés….
-
Java nyelven lehet appleteket írni, amelyek beszúrhatók HTML oldalakba
is
-
tökéletesen hordozható
-
az Internet-programozás fő nyelve
Érdekességképpen néhány régebbi programnyelv, amelyek elterjedtek voltak,
de ma már csak elvétve találkozni velük:
-
FORTRAN (FORmula TRANslator)
-
tudományos számítások
-
legmagasabb szintű adatstruktúra a tömb
-
ma főleg nagygépeken, vagy régi programok mélyén használják
-
COBOL
-
emberközeli szintaktika
-
adatbáziskezelés
-
ma (szinte kizárólag) nagygépen használják
-
PROLOG ( = PROgramming in LOGic)
-
matematikai logikán alapuló programozás
-
logikai problémák megoldásánál hatékony, de másra nehézkesen használható
-
mesterséges intelligencia kutatás
-
LISP ( = LISt Processing)
-
listafeldolgozás
-
funkcionális programozás
-
mai programok mélyén: pl. Emacs, AutoCAD
-
SMALLTALK
-
az első igazi objektum-orientált programozási nyelv
-
interpreteres megoldás
2. Adatok
Mivel a programok utasításai adatokon dolgoznak, ismerkedjünk meg először
ezekkel!
Minden adattípusnál meg kell nézni, hogy milyen értékeket képes tárolni,
hogyan ábrázolja a számítógép, és végül milyen műveleteket végezhetünk
velük.
2.1 Elemi (egyszerű) adattípusok
2.1.1 Logikai (boolean) típus
| felvehető értékek |
ábrázolás |
| false (hamis) |
0 |
| true (igaz) |
nem 0, legtöbbször 1 |
| műveletek |
asm
|
C/C++, Java |
| tagadás (negálás, invertálás) |
not |
! |
| és |
and |
&& |
| vagy |
or
|
|| |
| kizáró vagy |
xor
|
^ |
2.1.2 Numerikus (számok) típusok
2.1.2.1 Egész, (fixpontos,) integer típus
Ábrázolása kettes számrendszerben történik. Egy kettes számrendszerbeli
számjegy - egy bit.
Az ábrázolható számtartomány attól függ, hogy hány biten (n) történik
a tárolás:
|
ábrázolható számtartomány |
| előjel nélküli |
0 .. 2n-1
|
| előjeles |
-2n-1 .. 2n-1-1
|
Például egy n=16 bites előjeles egész esetében ez -215..215-1,
vagyis -32768..32785.
A mai gépek általában 8, 16, 32, 64 biten tárolják az egész számokat.
| Műveletek egész számokkal |
műveleti jel |
megjegyzés |
| negálás |
- |
|
| összeadás, kivonás, szorzás |
+ - * |
|
| (egész) osztás |
/ |
7/2=3 |
| maradék (modulus) képzés |
% |
7%2=1 |
növelés (inkrementálás),
csökkentés (dekrementálás) |
++
-- |
x++ jelentése: x = x + 1
x-- jelentése: x = x - 1 |
| Bitműveletek |
|
műveleti jel |
| tagadás (negálás, invertálás) |
not |
~ |
| és |
and |
& |
| vagy |
or |
| |
| kizáró vagy |
xor |
^ |
| shift (eltolás) balra |
shl |
<< |
| shift (eltolás) jobbra |
shr |
>> |
2.1.2.2 Valós (lebegőpontos) típus
|
neve |
| egyszeres pontosságú |
float |
| dupla pontosságú |
double |
Gépi ábrázolása normál alakban: Például: 0.00123 = 0.123 *
10-2 (megadása 0.123e-2)
Műveletek: + - *
/
Összehasonlítás: a kerekítések és az ábrázolási pontatlanságok miatt
használjuk az |a - b| < epsilon formulát!
2.1.3 Alfabetikus (betű alapú) típusok
2.1.3.1 Karakter (character) típus
| ábrázolása |
kódolás |
| 7/8 bit |
ASCII |
| 2 byte |
UNICODE |
Karakterkonstans: aposztrófok között, pl. : 'c', '\n'
(az utóbbi az új sor karakter)
2.1.3.2 String (szöveg) típus
Ábrázolása: karaktertömb/karakterfüzér.
Stringkonstans: dupla aposztrófok között: "Ez
itt egy sor\n"
2.2 Összetett adatok
2.2.1 Tömb
Adott számú (általában azonos típusú) adat együttese.
Dimenzió szerint:
-
1 dimenziós: vektor
-
2 dimenziós: mátrix
-
több dimenziós
Például:
-
egy számokból álló 5 elemű egydimenziós tömb:
-
speciális tömb: karaktertömb (string)
Indexelés:
A tömb minden elemének van egy sorszáma (ezt indexnek nevezzük). A indexelés
(vagyis a sorszámozás) általában 0-val kezdődik. Az egyes elemeket úgy
érhetjük el, ha a tömb neve után szögletes zárójelben megadjuk indexüket:
a t tömb második eleme t[2] (a fenti példában t[2]
értéke 0). Tehát egy t nevű n elemű tömb első eleme
t[0],
utolsó eleme t[n-1]. Az indexeléssel a tömbelemek úgy használhatók,
mint a közönséges változók.
2.2.2 Rekord/struktúra
Több, különböző títpusú adat együttese. Az összegyűjtött adatok a rekord/struktúra
mezőit képzik.
Például egy személy adatai:
| mező neve |
típus |
| nev |
string |
| szuletesiEv |
integer |
| vanErettsegije |
boolean |
Az egyes mezőkre általában ponttal elválasztva hivatkozunk, pl. ha az
ember
egy
fenti személy típusú változó, akkor az adott ember nevét jelentő mező:
ember.nev
2.2.3 Objektum
A rekordok/struktúrák továbbfejlesztése: az adattagokon (adatmezőkön) kívül
tagfüggvényeket (metódusokat) is tartalmaznak.
3. Algoritmikus programozás
3.1 Algoritmus
Az algoritmus olyan pontos előírás, amely megmondja, hogy egy adott
típushoz tartozó összes feladat (problémaosztály) megoldásához milyen műveleteket
kell meghatározott sorrendben elvégezni (vagyis pontosan megmondja,
hogy miként kell megoldani a problémát).
Kívánalmak:
-
véges lépésszámon belűl érjen véget
-
egyértelmű eredményt szolgáltasson
-
általános: ne csak egy konkrét feladatot oldjon meg, hanem lehetőleg
minél szélesebb problémaosztályt
(pl. ne csak egy konkrét másodfokú egyenletet, hanem bármilyen másodfokú
egyenletet)
Az egyes lépésekben elvégezhető műveletek Neumann-elvű számítógépek esetében:
-
egyszerű utasítások:
-
összetett utasítások:
-
utasítás blokk (több utasítás egyben)
-
vezérlési szerkezetek (program menetének befolyásolásához használhatók):
-
elágazások: döntési szerkezetek
-
ciklusok: ismétlési szerkezetek
Leírása:
-
algoritmus leíró nyelv
-
blokkdiagram
-
struktogram
3.2 Az értékadás
Elemi művelet, amely általában azonos típusú adatok között használható.
Segítségével valamely változóhoz új értéket rendelhetünk. Általános alakja:
változó = kifejezés
Olvasd: változó legyen egyenlő kifejezés.
Jelentése: először a jobb oldali kifejezés kiértékelődik, majd az eredmény
betöltődik a bal oldalon lévő változóba. A kiértékelendő kifejezés általában
tetszőlegesen bonyolult lehet, és tartalmazhat:
-
konstansokat (pl. 3)
-
változókat (pl. x)
-
függvényhívásokat (pl. sin(x))
-
operátorokat (műveleti jeleket) (pl. x + 2)
Pl:
z = y + 2*tan(x)
jelentése: számítsd ki az y + 2*tan(x) kifejezés aktuális értékét,
és az eredményt tedd bele az z változóba!
Ha az egyenlőség jel (pontosabban az értékadás operátor) két oldala
eltérő típusú, az alábbi dolgok történhetnek:
-
hibajelzést kapunk (gyakran már fordításkor)
-
automatikus típuskonverzió történik: az egyenlőségjel jobb oldalán
lévő kifejezés kiértékelése során kapott eredmény az egyenlőségjel bal
oldalán lévő változóval megegyező típussá konvertálódik.
Például JavaScriptben a szo = 5/10 értékadásnál a bal oldal
string, tehát a jobb oldal eredménye (a 0.5 szám) a "0.5" stringgé konvertálódik.
Különböző nyelvek eltérő szigorral kezelik a típusok keveredését. Ezek
alapján beszélhetünk
-
erősen típusos nyelvekről (pl. Pascal, C++, Java)
-
gyengén típusos nyelvekről (pl. JavaScript)
3.3 Függvények
A programozásban a függvények a matematikában használt függvények kiegészítései.
Egy függvény jellemzői:
-
van(nak) bemenő paraméter(ei)
-
csinál valamit
-
legfeljebb egyetlen visszatérési érték lehet (tehát vagy nincs, vagy 1
db van)
Például:
-
a sin(x) függvénynek egyetlen valós paramétere van, a kapott paraméter
szinuszát számolja ki, és ez az érték a visszatérési értéke.
-
a write(s) függvénynek egyetlen (string) paramétere van, amelyet kiír a
képernyőre, visszatérési értéke pedig nincs.
Függvényeket magunk is készíthetünk. Pl: kör kerületét kiszámító függvény
(algoritmus leíró nyelven):
függvény KörKerület ( sugár: Valós )
kerület = 2 * sugár * 3.14;
visszatérés: kerület
vége
Fejlesztői könyvtárak (library-k, lib-ek)
Hasonló témájú függvényeket gyakran helyeznek el együtt,
úgynevezett programozói könyvtárakban, library-kben.
A könyvtárak (mint külön elkészített modulok) eredetük
szerint:
-
,,beépített'': az adott fejlesztői környezethet (fordítóhoz)
adják, pl. rendszerhívások
-
vásárolható, vagy beszerezhető (pl. az Internetről letölthető)
-
saját készítésű
téma szerint például:
-
matematikai dolgok: pl. szögfüggvények... - ezeket általában
a fejlesztői környezet adja
-
felhasználói felület (user interface), ablakok programozása,
pl:
-
MFC: (Microsoft Foundation Classes) Windows programozáshoz
-
AWT: Java programozáshoz
-
3D grafika
-
OpenGL: (Silicon Graphics által)
-
Direct3D: (Microsoft által)
-
Java3D
-
rendszerhívások: az operációs rendszer szolgáltatásait lehet
segítségükkel elérni (pl. programból hozhatunk létre vagy törölhetünk fájlokat...)
-
hálózatkezelés (pl. socket interface a TCP/IP-hez)
Természetesen nem lehet minden könyvtárat minden nyelvből
elérni. Minden nyelvhez általában külön könyvtárak tartoznak.
3.4 Vezérlési szerkezetek
3.4.1 Elágazás (if)
A leggyakrabban használt elágazás az "if" (ha-különben típusú elágazás):
| blokkdiagram |
stuktogram |
algoritmus leíró nyelv |
JavaScript |
|
|
ha (feltétel)
utasítások
különben
utasítások
|
if (feltétel)
utasítások
else
utasítások
|
3.4.2 Ciklusok
3.4.2.1 Hátultesztelős ciklus (do-while)
Először végrehajtja a ciklusmagban lévő utasításokat, majd megvizsgálja
a feltételt (bennmaradási feltétel), és ha ez igaz, akkor újra végrehajtja
a ciklustörzset. Vegyük észre, hogy ha ez az első lefutásnál már hamis,
attól még a cikosmag mindenképp lefut egyszer.
| blokkdiagram |
stuktogram |
algoritmus leíró nyelv |
JavaScript |
|
|
ciklus
ciklusmag
amíg (feltétel) |
do
ciklusmag
while (feltétel) |
3.4.2.2 Elöltesztelős ciklus (while)
Először megvizsgálja a feltételt (belépési feltétel), és csak akkor hajtja
végre a ciklusmagban lévő utasításokat, ha a feltétel igaz. Vegyük észre,
hogy ha kiinduláskor már hamis a belépési feltétel, akkor egyszer sem fut
le a ciklustörzs.
| blokkdiagram |
stuktogram |
algoritmus leíró nyelv |
JavaScript |
|
|
ciklus amíg (feltétel)
ciklusmag
|
while (feltétel)
ciklusmag
|
3.4.2.3 For ciklus
Az elöltesztelős ciklus egy speciális esete, amikor a megadott ciklusváltozó
(gyakran i-nek nevezik) értéke minden lépés után automatikusan nő eggyel,
a kezdőértéktől (k.é.) a végértékig (v.é.).
| blokkdiagram |
stuktogram |
algoritmus leíró nyelv |
JavaScript |
| |
|
ciklus i = k.é. től v.é. -ig
ciklusmag
amíg (feltétel) |
(ez egy kicsit több annál)
for (i = k.é. ; i<v.é. ; i++)
ciklusmag
|
4. JavaScritp