Számítógép és programozás 2
3. Előadás Típuskonstrukciók
http://digitus.itk.ppke.hu/~flugi/
IS M ÉT LÉ S ●
● ●
Programkonstrukciók
Elágazás kell, ha más kódra van szükség egyes esetekben Ciklus kell, ha ismételni kell lépéseket Okos megbízható matematikusok eredménye: Minden algoritmikusan megoldható probléma megoldható szekvencia, elágazás és ciklus segítségével.
Mi a közös az eddigiek tételekben? ●
Tetszőlegesen hosszú sorozat feldolgozása
●
Kevés (max 5-6) változóval
●
Kizárólag elemenként feldolgozható feladatok
●
–
Minden elemet pontosan egyszer kezelünk
–
A sorrend kötött: csak abban a sorrendben tudunk olvasni, ahogy a sorozatban egymást követik
Ezeknek a fő oka, hogy a feldolgoznivaló adatsor sokszor nem fér a memóriába, tehát spórolni kell a memóriaigénnyel
A tömb ●
●
●
●
A tömb egy típuskonstrukció: egy egyszerű típust megsokszorozunk, adott hosszú sorozatát, mint típust kezeljük A tömb típusú változót közvetlenül ritkán, inkább a hordozott sorozat egy-egy tagját kezeljük VÁLTOZÓK: a: EGÉSZ[10] a[2]:=3 a2=3 Lényegében (nullától) indexelt, egyforma típusú változók egységes kezeléséről van szó
Példa tömbre PROGRAM PROGRAM tömb tömb VÁLTOZÓK: VÁLTOZÓK: a: a: EGÉSZ[10], EGÉSZ[10], i: i: EGÉSZ EGÉSZ ii := := 00 CIKLUS CIKLUS AMÍG AMÍG ii a[i] a[i] := := RND RND ii := := ii ++ 11 CIKLUS_VÉGE CIKLUS_VÉGE PROGRAM_VÉGE PROGRAM_VÉGE
<< 55
10 10 ++ 11
Tömbök ●
●
A tömb szabadon címezhető, tetszőleges sorrendben bejárható, átírható, kezdeti értéket nem tartalmazó változósorozat, ellentétben a bemeneten kapott sorozatokkal Viszont előre, fordítási időben tudni kell a méretét. –
Hallgatók rendszeresen abba a hibába esnek, hogy mindent tömbökkel akarnak megoldani. Ennek tipikus jele, hogy sorozatot akarnak beolvasni egy 1000 méretű tömbbe..
Tömbök ●
A tételek tömbökön is alkalmazhatóak, mivel ismert hosszú sorozatokról van szó, ahol az adott elem a sorszámával hivatkozható ... ... sum sum := := 00 ii := := 00 CIKLUS CIKLUS AMÍG AMÍG ii << 10 10 sum sum := := sum sum ++ a[i] a[i] ii := := ii ++ 11 CIKLUS_VÉGE CIKLUS_VÉGE ... ...
Többdimenziós tömb ●
● ●
●
●
A tömb szintaxisa szerint T[méret] a tömb, ahol T tetszőleges típus A tömb is típus Tehát a T[méret1][méret2] is helyes, és tömbök tömbjét jelenti Ez kétdimenziós tömb, két független indexet lehet használni, mint koordinátákat Természetesen tetszőlegesen fokozható a dimenziószám – elméletben. Gyakorlatban kifogyunk a memóriából.
Tömb: vektor, mátrix ●
Az egydimenziós tömböt szokás vektornak, kétdimenziósat mátrixnak nevezni VÁLTOZÓK: VÁLTOZÓK: a: a: EGÉSZ[10][10], EGÉSZ[10][10], i, i, j: j: EGÉSZ EGÉSZ ii := := 00 CIKLUS CIKLUS AMÍG AMÍG ii << 10 10 jj := := 00 CIKLUS CIKLUS AMÍG AMÍG jj << 10 10 a[i][j] a[i][j] := := RND RND 55 ++ 11 jj := := jj ++ 11 CIKLUS_VÉGE CIKLUS_VÉGE ii := := ii ++ 11 CIKLUS_VÉGE CIKLUS_VÉGE
Tömbök jelentősége ●
Olyan feladatoknál, ahol –
több adatra van szükség annál, mintsem külön változókban kényelmes lenne kezelni, fix számú, és még beleférünk a memóriába
–
többször kell kiértékelni ugyanazt az értéket
–
tetszőleges sorrendben kell hozzáférni az elemekhez
–
az adatokat módosítani is kell, nem csak olvasni .. rákényszerülünk a tömb használatára
Néhány példa ●
Képkezelő szoftverek a képet mátrixként tárolják –
●
● ●
konkrétan a FF szürkeárnyalatos képeket általában egész számok mátrixával ábrázolják
Hagyományos mátrixműveletek, Gauss elimináció, bázistranszformáció Táblázatos adatok A szöveg típus néhány művelettől eltekintve felfogható karakter-vektornak
Tömbök és a PLanG ●
●
●
A tömb típusú változók kiírathatóak, de nem beolvashatóak A változók értékeit mutató táblázatban az egész tömb követhető A tömbelemek kezdeti érték nélkül jönnek létre, erről gondoskodni kell
C és C++ ●
C tömb: típus változónév[méret] –
●
●
C++ inkább: vector
változónév(méret, kezdetiérték) A primitív tömb mérete fordítási időben ismert kell legyen –
●
„primitív tömb”
fordítóprogramok néha elfogadják a változót is, de az nem szabványos
Vector átadható paraméterként, többdimenziósan is
Típuskonstrukció és a vector #include #include using using namespace namespace std; std; int int main() main() {{ vector vector vektor(10,0); vektor(10,0); vector vector >> matrix(10,vector(10,0)); matrix(10,vector(10,0));
}}
vector vector >> >> tenzor(10, tenzor(10, vector vector >> (10, (10, vector(10,0))); vector(10,0)));
Összefoglaló ●
Tömbök: fix hosszú homogén változósorozat
●
Szintaxis: Típus[méret]
●
●
Akkor és csak akkor használandó, ha ismert hosszú, többszöri írást vagy olvasást, vagy tetszőleges sorrendben feldolgozást igényel a feladat Lehet több dimenziós
Típuskonstrukció ●
Meglevő típusokból új típus létrehozása
●
Eddigi példák: –
T v[10] : 10 darab T típusú változó alkot egy primitív vektort
–
T m[10][10] : 10x10 méretű (primitív) mátrix
–
vector v(10,t) : 10 darab T típusú változó alkot egy STL vektort t kezdeti értékekkel vector > m(10, vector(10, t)) : 10x10 méretű mátrix t kezdeti értékekkel
–
Típuskonstrukció ●
A struct: vegyes típusokból álló új típus
●
„rekord”
●
● ●
●
Az elv: az összetartozó adatok összetartozása jelenjen meg, mint nyelvi elem PLanGban ilyen nincs Példa: kétdimenziós koordinátákat eddig két tömbben tároltunk: double x[100] és double y[100] Mostantól írhatjuk majd C++-ban, hogy koord k[100]
struct #include #include using using namespace namespace std; std; struct struct koord koord {{ double double x,y; x,y; }; }; int int main() main() {{ koord koord k; k; k.x=1.0; k.x=1.0; k.y=1.0; k.y=1.0; cout cout << << "[" "[" << << k.x k.x << << "," "," << << k.y k.y << << "]" "]" << << endl; endl; return return 0; 0; }}
struct ●
●
● ●
●
A struct kulcsszó jelentése: most egy új típust fogok leírni struct név { T1 mező1, mező2..; T2 mezőX, ..; ... }; A típus neve bármi lehet, ami nem foglalt még T1, T2, .. típusoknak már ismert típusúak legyenek A mezőnevek különbözőek legyenek
A mezők ● ●
●
●
A struct mezőkből áll („tag”, angolul „member”) Minden mező egy már ismert típusba sorolható, és változóként használható: kaphat értéket, olvasható, referálható, stb. A mezők használatakor a struct típusú változók után '.' karakterrel elválasztva a mezőnevet kell írni Tehát az előző példában a 'k.x' jelentése: a k változó koord típusú, annak az x mezője, tehát egy double típusú érték
Mező vs változó ●
Változónak szokás nevezni mindent, amit külön deklaráltunk –
●
●
Mezőt a többi mező nélkül nem lehet deklarálni
Egy struct egy mezőjét külön nem deklaráltuk, de mégis úgy használjuk, mint egy változót: adunk neki értéket, kiolvassuk, stb A szóhasználat tehát nem a képességeket, hanem a szerepet fedi: önállóan használandó, vagy egy nagyobb adatcsoport része?
Mi legyen mező, és mi ne? ●
●
A mezők összessége mindig a struct szerepét teljesen töltse ki, és ne legyen benne felesleg „Reprezentáció”: egy absztrakt fogalom ábrázolása meglevő típusokkal –
●
●
pl. 2D koordináta két valós számmal, racionális szám két egész számmal, mint számláló és nevező
A ciklusváltozó például nincs a mezők között: nem tartozik a fontos adatokhoz Az viszont nem nagy baj, ha a teljes értékkészletek nincsenek kihasználva, pl. tanuló jegye int mező. Ez csak kis baj.
struct és a típusok ●
Az adott struct leírása után a megadott név már egy kész típus, használható deklarációkban, paraméterlistákban –
●
●
Akár egy következő struct mezőjénél is, vektorban, primitív tömbben, stb..
A struct mezője is lehet vektor, vagy primitív tömb Fontos, hogy a forráskód fentről lefelé olvasva ezt a sorrendet betartsa
struct összefoglalás ●
A struct akkor jó, ha –
A neve és a szerepe jól illeszkedik egymáshoz
–
A szerepe és a mezői között fennáll a kölcsönös szükségesség ●
●
–
Csak a „fontos” adatok vannak a mezők között (nem kerül bele irreleváns (pl. ciklusváltozó) vagy mindenhol egyforma adat) Minden „fontos” adat benne van
A mezők által meghatározott szerep és a felhasználás harmonikus ●
Minden mezőt felhasznál a feladat megoldása
Rövid kitérő a számábrázoláshoz ●
●
●
Az „EGÉSZ” illetve „VALÓS” típusok nevei azt a látszatot keltik, hogy a típusértékhalmaz a teljes egész illetve valós számokat fedi Ez természetesen lehetetlen, véges hosszú memóriaszeletek állnak rendelkezésre a számok ábrázolásához A fenti típusok tehát nem mindenben viselkednek a várakozásoknak megfelelően
Rövid kitérő a számábrázoláshoz ●
● ●
Például az EGÉSZ 32 bites szám, tehát legfeljebb 232 féle értéket vehet fel. Ezt praktikusan a -231 .. +231-1 tartományra tolták: -2147483648 .. 2147483647 → kettes komplemens kódolás Ennek az a következménye, hogy 2147483647 + 1 = -2147483648 –
●
vagy 16 biten (short): 32767+1=-32768
Ezt a jelenséget túlcsordulásnak nevezik
Rövid kitérő a számábrázoláshoz ●
●
●
A valós számok véges ábrázolása miatt pontatlan Számológépről ismerős lehet: 3 gyökének a négyzete 2.99999999 Ebből kifolyólag soha nem vizsgáljuk programban egy valós típusba tartozó változó egyenlőségét semmivel
Rövid kitérő a számábrázoláshoz ●
●
●
A valós számokat X * 2Y alakban tárolják, visszavezetve az egész számokra Pl 32 bites esetben 23 bit X-re, 8 bit Y-ra, plusz előjel Ennek következménye, hogy nem mindenhol egyformán sűrű az ábrázolás, ha 23 kettedesjegynél nagyobb a nagyságrendi különbség, akkor előfordulhat, hogy A ≠ 0, de A+B=B
forrás: xkcd