Úgy gondoltam, ha már tömböket kezelünk, akár megnézhetnénk a pointereket is. Szóval dinamikus memóriakezelés. Memóriát már eddig is kezeltünk, igaz akaratlanul, hiszen az összes változónk a memóriában van. A globális változók a heap-ben, a lokális változók pedig a stack-en foglalnak helyet. Ez annyit tesz, hogy a globális változók a program egész futási ideje alatt ott foglalják a memóriát, a lokális változók pedig csak akkor jönnek létre a stack-en, ha az adott függvény végrehajtásra kerül.

Pointer:

A pointer egy olyan változófajta, ami egy memóriarekeszre mutat. Segítségével írhatunk illetve olvashatunk a memória általa mutatott részéről. C-ben egy pointert úgy lehet deklarálni, hogy csillaggal kezdjük a változónevet. Pl.:

int *szamramutat;

Van egy pointerünk. De itt mit jelent az int ? Annak a memóriarekesznek a típusát amire a pointer mutat. Tehát már a deklaráció helyén illik adni, hogy mire fog mutatni. Ez egy 2 byte-os előjeles egész számra mutató pointer.

Persze akkor is tudunk pointert csinálni, ha még nem tudjuk, mire fog mutatni :

void *valamiremutat;

Ha a pointernevet csillaggal írjuk le, mindig az általa mutatott érteket jelenti, ha csillag nélkül, akkor pedig a pointer igazi értékét. Maga a pointer lehet 2 illetve 4 byte-os. Small memóriamodellben mindig a 2 byte-osal fogunk találkozni, ez a near pointer, az egy szegmensnél több adatot kezelő modelleknél pedig 4 byte-os, azaz far pointerekkel találkozunk. Ha külön ki akarjuk hangsúlyozni, hogy az adott pointer éppen milyen, akkor odaírjuk a típusát:

int near *mutat;

Nézzük akkor azt, hogy van egy pointerünk, amit frissen deklaráltunk. Hova mutat most ez ? A nagy nihilbe. Sehova. (NULL) Elvileg! Gyakorlatilag persze kell, hogy mutasson valahova. Az adatszegmens első byte-jára. Erre a tájékra a C direkt nem helyez semmi változót, nehogy egy sehova mutató pointerrel felülírjuk. Figyeli ezt a területet, és ha változik, null pointer assignment hibaüzenettel kiszáll. (mivel ezen terület eredetileg csupa nulla, azt nem fogja észrevenni, ha egy előkészítetlen sehova mutató pointerrel nullát írunk ide, hiszen így nincs változás) A rosszul előkészített pointerek még veszélyesebbek, hiszen segítségükkel a memória azon részét is felülírhatjuk, amihez semmi közünk. Ebből aztán rendszerint rendszerfagyi van. Tehát a pointert minden esetben helyesen elő kell készíteni. pl így:

mutato=&valtozo;

Az & jel annyit tesz, hogy megmondja a mögé írt változó címét. Ettől aztán a pointerünk erre a változóra fog mutatni. Segítségével ennek a változónak az értékét tudjuk változtatni. pl.:

int valtozo=79;

int *mutato;

mutato=&valtozo;

printf("%d",*mutato);

Eddig minden tiszta és világos.

Mire jó ez?

Mondjuk akarunk csinálni egy olyan függvényt, ami hozzáadja az első paraméterhez a másodikat. Pointerek nélkül nem boldogulnánk, ha beszarunk, akkor se tudjuk függvényen belülről megváltoztatni az eredeti paramétereket. De pointerekkel:

#include <STDIO.H>
void fugv(int *a,int *b)
{
*a+=*b;
}
void main(void)
{
int a=9, b=70;
fugv(&a,&b);
printf("%d",a);
}

Ha már itt tartunk, keverjük bele a tömböket is. Ha tömböt adunk át függvénynek paraméterként, az a szegény függvény csak a tömb kezdőcímét fogja megkapni:

rendez(int *tomb, int elem)
void main(void)
{
int tomb[30];
rendez(tomb,30);
}

Ugye mindenkinek feltűnt, hogy a függvényhívásánál nem kellett & jelet tenni a tömbnév elé. A tömb neve önmagában már csak a tömb címét jelenti.

Felvetődhet, hogy az a szerencsétlen fügvény most hogy fogja azt az egy szál pointert tömbként kezelni. Egyszerűen! Úgy kell csinálni, mintha tömb lenne. Ha elég meggyőzően játszunk, a compiler el is fogja hinni.

pl.:

#include <STDIO.H>
void mian(void)
{
int tomb[10]={1,2,3,4,5,6,7,8,9,0};
int *mutato;
int n;
mutato=tomb;
printf("Először a tömbből:\n");
for(n=0;n<10;n++) printf("%d\n",tomb[n]);
printf("Aztán a pointerrel\n");
for(n=0;n<10;n++) printf("%d\n",mutato[n]);
}

Persze egy tömböt pointerrel máshogy is átjárhatunk:

#include <STDIO.H>
void mian(void)
{
int tomb[10]={1,2,3,4,5,6,7,8,9,0};
int *mutato;
int n;
mutato=tomb;
printf("Először a tömbből:\n");
for(n=0;n<10;n++) printf("%d\n",tomb[n]);
printf("Aztán a pointerrel\n");
for(n=0;n<10;n++) printf("%d\n",*(mutato+n));
}

vagy igazán poinerként használva:

#include <STDIO.H>
void mian(void)
{
int tomb[10]={1,2,3,4,5,6,7,8,9,0};
int *mutato;
int n;
mutato=tomb;
printf("Először a tömbből:\n");
for(n=0;n<10;n++) printf("%d\n",tomb[n]);
printf("Aztán a pointerrel\n");
for(n=0;n<10;n++) 
{
printf("%d\n",*mutato);
mutato++;
}
}

C-ben elég nagy biztonsággal kezelhetünk pointerre mutató pointereket, vagy olyan pointert, ami pointerre mutató pointerre mutat, vagy olyan pointert, ami olyan pointerre mutat, ami pointerre mutató pointerre mutat, vagy olyan pointert, ami olyan pointerre mutat, ami egy olyan pointer, ami pointerre mutató pointerre mutat, vagy egy olyan pointert, ami olyan pointerre mutat, ami egy olyan pointer, hogy az általa mutatott pointer, egy pointerre mutató pointerre mutat,(Ápoló néni, hol a gyógyszerem ???????????!!!!!) vagy esetleg egy pointert, ami által mutatott pointer egy olyan pointerre mutat, ami által mutatott pointer szintén pointerre mutat, ami egy olyan pointerre mutat, ami valójában egy pointerre mutató pointer, de a poén kedvéért kezelhetünk akár olyan pointert, ami egy oly (Ne!!! nem kérek szurit !!!!!!!!!!!!)...

Nézzük:

#include <STDIO.H>
int valami;
int *mutato1; //ez fog mutatni a változóra
int **mutato2; //ez a változora mutató pointerre fog mutatni
int ***mutato3; //ez meg az előzőre
int ****mutato4; //meg ez is
int *****mutato5; //meg ez is
//és még folytathatnám
void main(void)
{
mutato1=&valami; //na az első már mutat valahova
mutato2=&mutato1; 
mutato3=&mutato2;
mutato4=&mutato3;
mutato5=&mutato4; //na mindenki a valamire mutat
*****mutato5=79; //remélem tényleg működik
printf("%d",valami);
}

Ennyit a pointerekről röviden

Asszem' a dinamikus memóriakezelést majd egy következő alkalommal.