Tömbök és memóriablokkok

 

Ha szükség van több azonos típusú adat egymás utáni tárolására a memóriában olyan célból, hogy ezeket indexek segítségével gyorsan és hatékonyan elérjük, akkor erre az adatszerkezetre tipikusan a tömböket szokás használni. A C nyelvben azonban ez a művelet megtehető egy memóriablokkra is, amennyiben ismerjük a típust, amelyből felépül, az első adat címét, amelyet 0-val fogunk indexelni. Azért jobb a memóriablokk szó, mert ezzel kifejezzük, hogy ezt futás közben is allokálhatjuk, míg a tömb, mint fogalom, inkább a fordítási időben történő változódefinícióhoz köthető, legalábbis klasszikus értelemben. Szokás használni erre a dinamikus tömb szót is, de ez azért megtévesztő, mert a programozás során a „dinamikus” és fordítási időben definiált tömb között az alább részletezett kivételtől eltekintve semmi különbség nincs.

 

Tömbök:

pld.

char a[80];   /* karakter típusú tömb */

 

A C nyelvben a klasszikus értelemben vett tömbökre csak a következő állítások tehetők:

·        Csak egydimenziós tömbök léteznek, ezek mérete konstans kell, hogy legyen már fordítási időben is. (A tömb tetszőleges elemekből állhat, akár tömbökből is, ami lehetővé teszi a kétdimenziós tömbök egyszerű szimulációját.)

·        Csak két művelet végezhető egy „klasszikus” tömbön: lekérdezhető a mérete a sizeof operátorral és előállítható a 0. elemére mutató pointer.

 

Minden más tömbökre alkalmazott műveletet úgy célszerű értelmezni, mint egy memóriablokkra vonatkozó műveletet, amely memóriablokk kezdete azonos a tömb kezdetével, a rá mutató konstans pointer szimbolikusan pedig a tömb neve.

Azaz mondhatjuk, hogy a tömb neve a kifejezésekben valójában a nulladik elemére mutató konstans pointer. Ez alól kivétel a sizeof operátor, de az is csak abban a blokkban (illetve értelemszerűen az azon belüliekben), amelyben a tömböt definiáltuk. Azaz, ha például függvénynek adjuk át paraméterként, akkor a függvény hívás előtt kiértékelődik minden kifejezés, ami a paraméterlistára kerül (lásd sequence point), azért itt már nem is beszélhetünk tömbről, csak pointerről. Ebből következően súlyos elvi hiba a függvényben a „tömb” méretét sizeof operátorral megtudni.

 

Pointerek:

pld.

char *p;  /* karakterre mutató pointer */

Minden pointer deklarációjából egyértelműen kiderül, hogy milyen típusú adatra mutathat. Az adat mérete megtudható a sizeof(*p) operátorral. A pointer által mutatott memóriaterület nem garantált, hogy valóságos adatot tartalmaz, sőt lehet, hogy nem is elérhető. A sehova nem mutató pointert NULL értékkel jelöljük.

A gyakorlatban a pointerek vagy egy tömb adataira mutatnak, vagy egy dinamikusan lefoglalt memóriablokkra.

pld.

int t[100];

typedef int *ptype;

int *p;

ptype p;

p=t;

p=(ptype)malloc(100*sizeof(*p));

A pointerek által mutatott adatot a * operátorral érhetjük el: i=*p;

 

Pointer aritmetika

A pointerekhez hozzáadható (kivonható) egy egész szám. Ilyenkor a pointer attól függően, hogy milyen típusú adatra mutat, az adott adatnak megfelelő mennyiségű memóriaterületet lép előre (vissza) egy összefüggő memóriablokkot feltételezve.

Értelemszerűen két pointer különbsége a köztük levő adatok számát adja.

 

Indexelés

A memóriablokk (és a tömb) indexelése az [] index operátorral tehető meg, amely azonban teljesen egyenértékű a * operátor megfelelő alkalmazásával, olyannyira, hogy definíció szerint:

X[Y] = *((X)+(Y))

Mivel az összeadás operandusai felcserélhetőek, ezért helyes a következő kifejezés is: 5[a].

Azaz az index operátor és a pointer aritmetika között csak formai különbség van.

 

Stringek

A stringek olyan speciális memóriablokkok, melyeknek eleme char típusú, lefoglalt hossza nem feltétlenül ismert, de logikailag az utolsó elemük a bináris 0 karakter ('\0').

 

Inicializálás

int t[4]={1,2};

            A t tömb nulladik eleme 1, első 2, a többi 0.

char a[10]="alma";

            Az a tömb első 4 karaktere sorban 'a','l','m','a' lesz, a többi 0.

double r[]={4.5,7,9}

            Az r tömb mérete 3*sizeof(double) lesz, elemei sorban 4.5,7,9.

char b[]="alma";

            A b tömb mérete 5 lesz, elemei pedig sorban 'a','l','m','a','\0'.

char *p="alma";

            A p-vel megcímezhető memóriablokk csak olvasható, tartalma sorban

'a','l','m','a','\0'.

            A p értéke változtatható (például p++ jó),

de (az általa mutatott memória) tartalma nem (például *p='c' hibás).