Pointers

Een variabele

Een variabele in C/C++ gebruikt geheugenruimte. C++ classes gebruiken pas geheugenruimte als je er objects van maakt. Die objects gebruiken wel geheugenruimte, zie verderop bij Something.

Macro's zoals #define SAMPLERATE 48000 gebruiken geen geheugenruimte. Dit is namelijk text-vervanging: overal waar SAMPLERATE staat in de code wordt het door de preprocessor vervangen door 48000 voordat het de compiler in gaat.

Maar we gaan verder met variabelen en objects. Als we aannemen dat een char in het geheugen één byte ruimte nodig heeft en dat het geheugen in bytes georganiseerd is dan kun je de situatie voorstellen als hieronder. Adressen zijn in hexadecimale notatie.



Je ziet een plek in het geheugen waar een getal in staat, namelijk het getal dat volgens de ASCII-tabel correspondeert met de letter 'a'. Zoek eens op welk getal dat is met
man ascii

Deze geheugenplaats heeft een label letter. Dat is de naam van de variabele. Het label weet ook dat het hier gaat om een char, wat in C++ onder meer betekent dat het in één byte past.

In C++ schrijf je dit op als
char letter = 'a';
en dan denk je misschien "ja dat weet ik ook wel", maar realiseer je je dat dit twee stappen zijn?
  1. maak geheugenruimte vrij voor het bewaren van een char
  2. schrijf het getal dat overeenkomt met 'a' in die geheugenruimte

In werkelijkheid zal geheugen meestal niet per byte toegankelijk zijn maar bijvoorbeeld per 8 bytes (64 bits) en een char zal misschien een hele 64-bits-plek innemen of samengevoegd worden met andere chars. Bovendien gebruiken pointers in de volgende voorbeelden 4 bytes, wat in werkelijkheid vaak 8 bytes zullen zijn, maar het gaat om het idee.

Een pointer naar een variabele

Hieronder zie je een pointer letterPointer die geheugenruimte gebruikt. Een pointer is namelijk in essentie ook een variabele. Als je een pointer maakt maar geen waarde geeft dan kan er een willekeurige waarde in staan.
Wanneer we de pointer een waarde geven dan kunnen we deze gebruiken om naar een plaats in het geheugen te wijzen. In het volgende plaatje wijst letterPointer naar de geheugenplaats van de variabele letter doordat we het adres van de variabele letter (hier hexadecimaal 0x0d of in tientallig stelsel 13) aan letterPointer toegekend hebben. Tel maar na als je het precies wilt weten: 'a' staat op plaats 13.
char letter = 'a';
char *letterPointer = &letter;
We kunnen nu de inhoud van letter op twee manieren benaderen: via de variabele letter en via letterPointer:

std::cout << letter  << std::endl;
std::cout << *letterPointer << std::endl;

Het sterretje voor letterPointer geeft aan dat we niet de inhoud van letterPointer willen zien maar de inhoud van de plaats waar letterPointer naar wijst.

In de volgende plaatjes zie je telkens hetzelfde principe: een pointer die het adres krijgt van de eerste byte van een variabele en door middel van het type van de pointer weet uit hoeveel bytes de variabele bestaat. Zo heb je bijvoorbeeld een char-pointer, int-pointer, pointer naar double of pointer naar een object.

Merk op dat in alle gevallen de pointer zelf 4 bytes nodig heeft, onafhankelijk van waar die naar wijst.


int year = 0x7e2;
int *yearPointer = &year;



long year = 0x7e2;
long *yearPointer = &year;



Something something;
Something *somethingPointer = &something;

void pointers


void* aPointer;
Een void pointer is een pointer waarvan je alleen weet naar welke plek in het geheugen hij wijst, maar aan de pointer zelf kun je niet zien wat voor data op die plek staan. Je weet dus niet of er een int, long, double of eigen type verwacht wordt maar alleen waar naartoe de pointer wijst. Je bent als programmeur verantwoordelijk om aan te geven hoe je de data waar de pointer naar wijst wilt interpreteren.

Wandelen met pointers

Een pointer hoeft natuurlijk niet zo lang je programma draait naar dezelfde plek te wijzen. Je kunt er een ander adres in schrijven en dan iets lezen of schrijven op de plek waar deze dan naartoe wijst. Zo kun je bijvoorbeeld door een array heen wandelen:
std::string names = {"Kees","Marie","Tom","Els"};
std::string *namePointer=names;

  for(int name=0; name<4; name++){
    std::cout << *namePointer << std::endl;
    namePointer++;
  }

Let bij dit voorbeeld wel op dat je niet buiten de array leest of schrijft. Als je 4 verandert in 5 of 10 of 20000 gaat de compiler dit gewoon toestaan. Het programma zal misschien niet crashen maar het gedrag is onvoorspelbaar. Voer het een paar keer uit en kijk wat er gebeurt. Als het niet uit zichzelf stopt dan kun je ^C (control-C) gebruiken.

Voorbeelden van pointers

Hier staan diverse voorbeelden