Programozás‎ > ‎

Tömbök használata

A tömb általában azonos típusú változók sorszámozott példányainak tárolására használható. A sorszámot indexnek nevezzük, az adott indexű elem elérését indexelésnek. Az indexet általában a tömb neve után írt szögletes zárójelben adjuk meg.

a[4] = 3

b[i] = b[i-1] + b[i-2]

Indexek

A tömbök indexeléséhez általában egész számokat és egész típusú változókat használhatunk. Előfordul az is (pascal), hogy a nyelv definiálja felsorolható típusoknak egy halmazát, és ezek mind használhatók indexként. 

A programozási nyelvek egy családjánál (C, C++, Java,...) a tömböket mindig nullától indexeljük. Ezért egy N-elemű T tömb elemei így néznek ki:

T[0]    T[1]    T[2]     ...    T[N-1]

Más nyelvek esetében (pl. pascal) szokás, hogy egytől kezdjük az indexelést, illetve az is lehet, hogy tetszőleges index-intervallum megadható.

Túlindexelés

Ha a futás során egy index nincs benne a tömb megengedett indexeinek tartományában, akkor többféle hibajelenséget tapasztalhatunk:
  • futási idejű hiba (runtime error) és a program leállása;
  • túlindexelési kivétel kiváltása;
  • "szegmentációs hiba" / "general protection fault" és a program leállása;
  • véletlenszerű viselkedés.
Vannak olyan nyelvek is, amelyek fordítási időben is végeznek index ellenőrzést. Nyilván ez akkor lehetséges, ha konstans kifejezést használunk indexnek és a tömb mérete is adott fordítási időben.

Méret megadása, memória lefoglalása

A tömb mérete határozza meg, hogy mennyi memória kell tárolásához, ezért fontos kérdés, hogy mikor derül ki ez a memóriaigény.
  1. statikus tömbök: a tömb méretét fordítási időben meg kell adni. Sokszor az ilyen tömbök az adatszegmensben lesznek lefoglalva. Ha nem tudjuk előre, hogy a futás során hány elemet kell majd tárolnunk, akkor valamilyen felső becslést kell találnunk, és a "legrosszabb esetre" készülve kell memóriát foglalnunk. A tényleges elemszámot egy változóban kell nyomon követnünk.

  2. dinamikus tömbök: a tömb elemeinek típusát kell csak fordítási időben megadnunk, a méretet pedig futási időben. Ilyenkor általában a "new" operátor használható a memóriafoglaláshoz, és a tömb ott jön létre, ahol a többi dinamikus adatszerkezet (heap). Ha túl nagy tömböt próbálunk lefoglalni, akkor kivételt / futási idejű hibát kaphatunk.
Mindkét esetben igaz, hogy ha megadtuk a tömb méretét (akár fordítási, akár futási időben), onnantól kezdve ez a méret már nem változik. Ha átméretezhető tömbre van szükségünk, akkor ezt meg kell írnunk (vagy valamelyik sztenderd könyvtári adatszerkezetet használhatjuk). Az átméretezés úgy történik, hogy amikor elfogyott a hely a tömbben, akkor lefoglalunk egy kétszer nagyobbat, és annak elejére másoljuk az eddigi elemeket. A duplázás miatt egyre ritkábban lesz szükségünk erre a másolási lépésre, így átlagosan nem veszítünk sokat a tömb hatékonyságából.

Kezdőértékek

A nyelvtől függ, hogy a létrehozott tömb elemeinek feltételezhetünk-e valamit az értékéről. A Java például hozzárendel kezdőértéket a primitív típusaihoz, ezért egy int tömb minden eleme nulla kezdetben, egy boolean tömb elemei pedig kezdetben false értékűek.

C-ben és Pascal-ban a kezdőérték attól függ, hogy globális vagy lokális változóról van szó. A lokális változók általában a verem szegmensben jönnek létre és nem kapnak kezdőértéket, ezért hibát okoz, ha nem inicializáljuk őket.

Tömbök különböző programozási nyelvekben

Pascal

C

C++

Java


Példa: maximum kiválasztása

// T egy N-elemű tömb, számokat tartalmaz

max := T[0]
Ciklus i := 1-től (N-1)-ig
    Ha T[i] > max akkor
        max := T[i]
    Elágazás vége
Ciklus vége
Ki: max