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="
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).