Pointerek

BecomeAnXcoder – Pointerek

Figyelmeztetés!

Ez a fejezet haladó témát tartalmaz és a C nyelv alapvető fogalmait tárgyalja, ami kezdőknek félelmetes lehet első olvasásra. Nem kell megijedni, ha itt nem sikerül mindent megérteni. Szerencsére ahhoz, hogy elkezdjünk programozni az Objective C nyelvben, nem szükséges maradéktalanul megérteni az egyébként hasznos területet: hogyan működnek a pointerek (mutatók).

Bevezető

Amikor definiálsz egy változót, a Mac lefoglal egy memóriaterületet, ahol majd ennek a változónak a tartalmát fogja tárolni. Példaként nézzük a következő utasítást:

//[1] 
int x = 4;

Ahhoz, hogy futtatni lehessen ezt a kódot, a gépednek kell találnia egy kis üres helyet a memóriában és meg kell jelölnie, hogy ez az a terület ahol az x nevű változó értéke tárolva lesz (természetesen tudnánk és tanácsos is ennél beszédesebb változónevet választani). Vessünk egy pillantást még egyszer az [1]-es utasításra. A változó típusának megadása (itt most int) meghatározza, hogy mekkora területet kell az x változó számára lefoglalni. Amennyiben ez a típus long long vagy double lenne, akkor több helyre lenne szükség.

Az x = 4 értékadó utasítás a 4 értéket elhelyezi a lefoglalt területre. Természetesen a számítógéped emlékezni fog arra, hogy az x nevű változó értékét a memória mely területére helyezte el, vagy más szavakkal mondva arra, hogy mi a címe az x változónak. Ezután minden egyes alkalommal, amikor használjuk az x változót a programunkban, a számítógéped meg fogja találni a megfelelő helyen (a megfelelő címen) az x változó aktuális értékét.

A pointer (mutató) egyszerűen egy változó amelyik egy másik változó címét tartalmazza.

Változó hivatkozások

Egy változó címét megkaphatjuk, ha a neve elé egy & jelet írunk. Például a &x megadja az x címét.

Amikor a számítógép kiértékeli az x kifejezést, akkor az x változó értékével tér vissza (példánkban ez a visszatérési érték a 4). Ezzel szemben, amikor a &x kifejezést értékeli ki, akkor az x változó címével tér vissza, és nem az ott tárolt értékkel. A cím egy olyan szám, amelyik egyértelműen megjelöli a memória egy adott szeletét (mint ahogy a szobaszám is egyértelműen megjelöl egy szállodai szobát).

Pointerek használata

Egy pointert a következőképpen deklarálhatunk:

//[2] 
int *y;

Ez az utasítás definiál egy y nevű változót, amelyik tartalmazni fogja egy egész típusú változó címét. Még egyszer: ez nem egy egész típusú változót tartalmaz, hanem annak a címét. Ahhoz, hogy az y változó tartalmazza az x változó címét (másképpen mondva: az y-hoz hozzárendeljük az x címét ), a következőt kell írni:

//[3] 
y = &x;

Most y az x címére “mutat”, azaz azt tartalmazza. Az y segítségével ezért megkaphatjuk x tartalmát is, méghozzá a következőképpen.

Ha egy pointer neve elé egy csillagot írunk, akkor megkapjukannaka változónak az értékét, amire a pointer mutat. Például ha kiértékeljük a

*y

kifejezést, akkor ez a 4 értéket fogja szolgáltatni. Ez ugyanaz, mintha az x kifejezést értékeltük volna ki. Végrehajtva a következő utasítást:

*y = 5

ez egyenértékű azzal, mintha az

x = 5

utasítást hajtottuk volna végre.

A pointerek nagyon hasznosak, mivel időnként nem egy változó értékére, hanem a változó címére szeretnénk hivatkozni. Például szeretnél írni egy kis programot, ami eggyel megnöveli egy változó értékét. Vajon működni fog a következő programrészlet?

//[4] 
void increment(int x) { x = x + 1; }

Ez bizony sajnos nem fog jó eredményt szolgáltatni! Amennyiben meghívod ezt a függvényt egy programból, akkor nem a várt eredményt fogod megkapni:

//[5] 
int myValue = 6;
increment(myValue); 
NSLog(@"%d:\n", myValue);

Az eredmény 6 lesz. Miért is? Hát nem növeltük meg a myValue változó értékét azzal, hogy meghívtuk az increment függvényt? Nem, ez most nem történt meg. Ugyanis a [4]-ben levő függvény csak átveszi a myValue változó értékét (azaz a 6-ot), megnöveli eggyel, aztán nem csinál vele semmit. A függvények csak az átadott változó értékekkel dolgoznak és nem a változókkal magukkal, amelyek ezeket az értékeket tartalmazzák. Azzal, hogy megnöveled az x értékét (ahogy ez a [4]-ben meg is történik), ezzel csak a függvény által megkapott értéket növeled meg. Minden ilyen változtatás elveszik, ha ebből a függvényből visszatérünk. Sőt itt az x változónak sincs jelentősége, gondold csak végig mit várhatsz eredményül itt az increment(5); függvényhívástól?

Amennyiben szeretnél egy működő változatot írni erre a feladatra, tehát egy olyan függvényt, amelyik elfogad változókat bemenetként és megnöveli azok értékét, akkor a változó címét kell átadnod! Ekkor már nem csak használni tudod a változóban tárolt aktuális értéket, hanem meg is tudod változtatni azt. Ehhez egy pointert kell megadnod az argumentumban:

//[6] 
void increment(int *y) 
{
     *y = *y + 1; 
}

és ezt így tudod meghívni:

//[7] 
int myValue = 6;
 increment(&myValue); // a cím továbbküldése
 // most már a myValue értéke egyenlő lesz 7-tel

eredeti oldal