Weblessen.nl - Voor iedereen die wat wil leren..


C

Index
C Index
Voorwoord
De eerste stap
Een inleiding tot C
Programma besturing
Toekennen en Logisch vergelijken
Funkties en Variabelen
Defines en Macros
Strings en Tabellen
Pointers
Standaard Invoer / Uitvoer
Bestands Invoer / Uitvoer
Structuren en Unions
Dynamisch ngeheugen aanvragen
Karakter- en bitmanipulatie

Appendix
Hungarian Notation
Voorbeeldprogramma's
Totaal programma
Scherm- en bestands beschrijvingen
Aanpassingen voor VM/CMS

Pointers

 

Een beschrijving van de pointer

Eenvoudig gezegd is een pointer een geheugen adres. In plaats van een variabele is het een pointer naar een variabele, die ergens in het geheugen van de computer is opgeslagen. Bestudeer het programma POINTER1.C voor een programma met gebruik van pointers. main () { int index, *pt1, *pt2; index = 23; /* willekeurige waarde */ pt1 = &index; /* het adres van index */ pt2 = pt1; printf ("De waarden zijn: %d, %d en %d\n", index, *pt1, *pt2); *pt1 = 77; /* verander index */ printf ("De waarden zijn: %d, %d en %d\n", index, *pt1, *pt2); } Het programma begint met de declaratie van index en twee andere variabelen, waarvan de naam begint met een sterretje. In het eerste statement wordt aan index de waarde 77 toegekend. Dat is geen verrassing, dat deden we vaker.

Het tweede statement zegt dat aan variabele pt1 een vreemd uitziende waarde moet worden toegekend, namelijk de variabele index met een ampersand ervoor. In dit voorbeeld stellen pt1 en pt2 pointers voor, de variabele index is slechts een integer. Nu hebben we wel een probleem. We hebben nog niet geleerd hoe we met pointers in een C programma om moeten gaan. Daartoe moeten we eerst wat definities geven.

De volgende drie regels zijn hierbij belangrijk en moeten goed tot je doordringen.

  1. De naam van een variabele met een ampersand ervoor definieert het adres van die variabele en is daardoor een pointer naar die variabele. Om die reden kun je regel 6 van het programma lezen als: pt1 krijgt de waarde van het adres van index.


  2. De naam van een variabele met een sterretje ervoor in de declaratie, definieert die variabele als pointer van het gedeclareerde type. int *pt1 declareert dus pt1 als zijnde een pointer naar een integer.


  3. Een pointer met een sterretje ervoor in een statement, refereert aan de waarde van de variabele waarnaar de pointer wijst. Regel 9 van het programma kan worden gelezen als: de variabele waar pt1 naar wijst krijgt de waarde 23. Omdat pt1 naar index wijst, wordt aan variabele index dus de waarde 23 toegekend.
pt1 en pt2 zijn pointers en als zodanig bevatten zij dus altijd een geheugenadres. In het voorbeeld krijgt pt1 het adres van index en vervolgens wordt aan pt2 de waarde van pt1 toegekend. Het resultaat hiervan is dat ook pt2 naar de variabele index wijst. Wees er echter bewust van dat een niet geinitialiseerde pointer toch een waarde kan bevatten. Deze waarde wijst dan naar een onbekende plaats in het geheugen en dat kan tot vervelende verrassingen leiden.

Naar een variabele mogen meerdere pointers wijzen. In het voorbeeld programma zijn de uitdrukkingen index, *pt1 en *pt2 volkomen identiek. Dit wordt getoond in het printf statement.

Op regel 9 wordt de waarde van index gewijzigd met behulp van de pointer. Doordat er een sterretje voor de naam van de pointer staat, wordt gerefereerd aan de inhoud van het geheugen adres waar de pointer naar wijst. Het statement op regel 9 kent dus aan variabele index de waarde 23 toe.

In eerste instantie denk je misschien dat er drie variabelen zijn, maar er is er maar een. Er is een integer variabele en twee pointers die er naar wijzen. Dit wordt getoond met de toekenning op regel 9 en het laatste printf statement.

Pointer worden veel toegepast in C. Het verdient daarom aanbeveling tijd uit te trekken om dit onderwerp goed te bestuderen. Compileer en test het programma.


Declaratie van pointers

Kijk eens naar de volgende declaratie: int index, *pt1, *pt2; De variabele index wordt hier op de reeds bekende wijze gedeclareerd als zijnde een variabele van het type integer. Daarachter staan twee extra declaraties. De tweede declaratie kan worden gelezen als: de geheugenlocatie waarnaar pt1 wijst behoort bij een variabele van het type integer. Om die reden zeggen we pt1 is een pointer naar int. Evenzo zeggen we pt2 is een pointer naar int.

Een pointer moet dus altijd worden gedeclareerd als wijzend naar een variabele van bepaald type. Wordt de pointer ooit gebruikt als wijzend naar een variabele van een ander type, dan zal dat op uitvoeringstijd resulteren in een Type incompatibility error. Als het type van te voren niet bekend is, kan een pointer worden gedeclareerd wijzend naar het type void, een loos type of zo je wilt een universeel type. Dat gaat als volgt:

void *ptr;

De string als pointer

We hebben het terrein van de pointers al aardig ontgonnen, maar er is meer. We weten nog niet alles, dus lees gauw verder over dit belangrijke onderdeel van de programmeertaal C. Bestudeer het programma POINTER2.C om de cursus te vervolgen. main () { char een, twee, *ernaar, string[40]; int *pt, lijst[100], index; strcpy (string, "Dit is een string van karakters\n"); een = string[0]; twee = *string; /* een en twee zijn identiek */ printf ("1: een is %c en twee is %c\n", een, twee); een = string[11]; twee = *(string+11); /* een en twee zijn identiek */ printf ("2: een is %c en twee is %c\n", een, twee); ernaar = string + 11; printf ("3: element 12 is %c\n", string[11]); printf ("4: element 12 via pointer is %c\n", *ernaar); for (index = 0; index < 100; index++) lijst[index] = index + 100; pt = lijst + 23; printf ("5: element 24 is %d\n", lijst[23]); printf ("6: element 24 via pointer is %d\n", *pt); } In dit programma worden verschillende variabele gedeclareerd, waaronder twee pointers. De eerste pointer, ernaar genaamd, is een pointer naar een character variabele en de tweede pointer, pt genaamd, is een pointer naar een integer variabele. Verder zijn er nog twee tabellen gedeclareerd, string en lijst. Deze zullen worden gebruikt om de relatie te tonen die er bestaat tussen pointers en de naam van een tabel.

In de programmeertaal C is een string variabele eigenlijk gelijk aan een pointer naar de eerste letter van een string. Dit behoeft enige uitleg. Kijk daarom naar het voorbeeld programma. Allereerst wordt de variabele string gevuld met tekst, zodat we een en ander kunnen uitproberen. De eerste letter van de string wordt toegekend aan de variabele een wat een character variabele is. Hetzelfde doen we voor variabele twee, echter nu via de pointer. string wijst naar de eerste letter en *string refereert aan de inhoud. Het gevolg is dat beide character variabelen de letter D zullen bevatten.

In het algemeen zal string zich als pointer gedragen. Er is echter een beperking die een echte pointer niet kent. De waarde kan niet worden gewijzigd, zoals bij een variabele, doch is constant. De compiler zal deze pointer zijn initiële waarde geven en gedurende zijn levensduur zal hij naar de eerste letter van de string wijzen.

Op regel 12 wordt aan de variabele een de twaalfde letter van de tekst toegekend (de subscript begint immers bij 0) en krijgt variabele twee dezelfde waarde. Het is toegestaan in C een pointer te indexeren, zoals hier gebeurt met de waarde 11, om zodoende een letter verderop in te string te verkrijgen. Beide variabelen bevatten nu de letter s.


Pointer berekening

De C compiler zal, wanneer we pointers gaan indexeren, automatisch de juiste aanpassingen maken afhankelijk van het type variabele waar de pointer naar wijst. Zo zal bij character variabelen de pointer uit het voorbeeld eenvoudigweg met 11 opgehoogd worden, omdat character variabelen 8 bits ofwel 1 byte breed zijn. In geval we met een pointer naar int werken, wordt de index verdubbeld, omdat een integer variabele 16 bits ofwel 2 bytes breed is (op sommige computers zelfs 4 bytes!). Later, als we de structuren behandelen, zullen we ontdekken dat een variabele veel, heel veel bytes in het geheugen kan beslaan. Ook bij dit soort variabelen zal de C compiler het indexeren correct uitvoeren.

Omdat de variabele ernaar een pointer naar char is, kan er het adres van de twaalfde letter aan worden toegekend (string wijst naar de eerste letter; met 11 erbij wijst ernaar dan naar de twaalfde). In principe kan de pointer elke waarde krijgen. Het is de programmeur die ervoor moet zorgen dat de pointer binnen de grenzen van de tabel wijst. Door altijd op het type van de pointer te letten, zal indexering door de compiler op de juiste wijze geschieden.

Niet alle vormen van berekening zijn toegestaan op pointers. Het moet zinvol zijn, immers een pointer is willekeurig adres in het computer geheugen. Het is bijvoorbeeld zinvol een constante bij een pointer op te tellen, waardoor de pointer een beredeneerd aantal plaatsen verderop in het geheugen wijst. Zo lijkt ook aftrekken van waarden zinvol, om de pointer een beredeneerd aantal plaatsen terug te laten wijzen. Twee pointers bij elkaar optellen is weinig zinvol, omdat het optellen van twee adressen irrelevant is. Zo is ook het vermenigvuldigen van pointers niet zinvol. Denk er maar eens over na wat je dan eigenlijk aan het doen bent.

We gaan nog even terug naar het voorbeeld programma. De elementen van de tabel met de naam lijst krijgen achtereenvolgens de waarden 100 tot en met 199, als gegevens om te testen. Daarna gaat pointer pt wijzen naar het 24ste element. Dit element wordt dan op twee verschillende manieren afgedrukt (het getal 123), om aan te tonen dat het systeem werkelijk zal indexeren voor een integer variabele. Probeer dit programma geheel te begrijpen, voordat je verder gaat met het volgende hoofdstuk. Verander eens wat waarden. Compileer en test nu dit programma.


Parameter overdracht met behulp van pointers

In de vorige les hebben we gezien dat het mogelijk is om gegevens terug te geven vanuit een functie aan het aanroepend programma met behulp van tabellen. Een andere manier is, je raadt het al, met behulp van pointers. Bestudeer het programma TWEEKANT.C om te zien hoe we gegevens twee kanten op kunnen sturen, naar een funktie en vanuit een funktie. main () { int pindas = 100; int appels = 101; printf ("main: De startwaarden zijn %d en %d\n", pindas, appels); doewat (pindas, &appels); printf ("main: De eindwaarden zijn %d en %d\n", pindas, appels); } doewat (noten, fruit) int noten; /* noten is een integer */ int *fruit; /* fruit is een pointer naar een integer */ { printf ("doewat: De startwaarden zijn %d en %d\n", noten, *fruit); noten = 135; *fruit = 975; printf ("doewat: De eindwaarden zijn %d en %d\n", noten, *fruit); } In het hoofdprogramma worden twee integer variabelen gedeclareerd, pindas en appels. Geen van beide is dus een pointer. Aan beide variabelen wordt een waarde toegekend en we drukken ze af. Dan wordt de funktie doewat() aangeroepen met twee parameters. De eerste parameter is de variabele pindas zelf, de tweede parameter is het adres van de variabele appels. Hier ontstaat een klein probleem. De twee parameters zijn niet eender. We moeten de funktie vertellen dat de eerste een integer is en de tweede een pointer naar een integer. Dit is niet zo moeilijk. Binnen de funktie doewat() wordt gewerkt met de variabelen noten en fruit, waarbij de eerste is gedeclareerd als integer en de tweede als pointer naar een integer. De aanroep in het hoofdprogramma is daarmee in overeenstemming met de functie definitie en de interface zal dus correct werken.

De funktie drukt de waarden van beide variabelen af, wijzigt ze beiden met een fantasie waarde en drukt ze vervolgens nog eens af. Tot zover zal dit je duidelijk zijn. De verrassing komt als de funktie terugkeert en het hoofdprogramma de waarden nogmaals afdrukt. Je zult ontdekken dat de variabele pindas weer zijn oorspronkelijke waarde heeft, terwijl de variabele appels de waarde uit de funktie heeft gekregen. Dit komt doordat de funktie voor pindas een kopie heeft gemaakt. Voor de variabele appels werd een kopie van de pointer gemaakt. Deze kopie wijst naar de originele variabele en daardoor wordt de originele variabele veranderd. De laatste printf() toont daarvan het bewijs.

Door het gebruik van pointers bij de aanroep van een funktie, hebben we binnen de funktie toegang tot de gegevens erbuiten en kunnen we deze gegeven veranderen. Na terugkeer blijven deze veranderingen dan in tact. Wanneer je binnen de funktie de waarde van de pointer aanpast, zal bij terugkeer de waarde van de pointer in het aanroepende programma niet gewijzigd zijn. De pointer was immers een kopie. Je kunt hier gebruik van maken als je wilt.

In het voorbeeld was geen sprake van een directe pointer, maar van een adres. In veel programma's zul je echter met echte pointers werken, zoals programma's waarin gebruik wordt gemaakt van stadaard Invoer- en Uitvoer funkties. Die worden behandeld in de volgende lessen. Compileer en test het programma.

In het begin zul je wat huiverig zijn in het gebruik van pointers. Je zult echter ontdekken dat bij toenemende ervaring je meer een meer het nut en het gemak van pointers gaat waarderen, waardoor je ze ook meer en meer zult toepassen. Zeker op het terrein van In- en Uitvoer naar bestanden en dynamisch geheugen aanvragen, zijn pointers onmisbaar.



Webdesign

Maak van Weblessen.nl uw startpagina!
Plaats Weblessen.nl bij uw favorieten. Neem contact met me op.
Heb je een Hosting?
Geef hier jouw mening over jouw web hosting

Webadres.info: Goede domeinnaam kiezen

Gesponsorde links:
Budget Webhosting
Web2host.nl
10eurohost.nl
Denit Hosting Solutions
YourHosting.nl
Starthosting.nl
Eduvision.nl
Educruitment.nl
Webadres.info


De link top 5:
Gratis Computercursussen
WebmasterStartpagina
MijnStartpagina.nu
Bluebird Animatie
Anouksweb
Link aanmelden
Alle Partners

Webmasterwoordenboek
A | B | C | D | E | F
G
| H | I | J | K | L | M
N
| O | P | Q | R | S | T
U | V | W | X | Y | Z

Films vanavond op Tv:

De klok:

(advertentie)

HTML leren
PHP cursus
XML lessen
XHTML les
CSS leer
leer C
REXX online
Red Hat Linux cursus