Waarom C-pointers belangrijk zijn: hoe Pass-by-Pointer echte gegevenswijziging mogelijk maakt

8

De meeste ontwikkelaars komen pointers in C tegen via een specifiek mechanisme dat bekend staat als pass-by-pointer. Het is niet alleen een syntaxisfoutje; het is de fundamentele reden waarom functies de externe toestand kunnen wijzigen. Waarschijnlijk heb je dit al eerder gezien zonder dat je het doorhad. Denk eens aan de scanf -functie. Elke keer dat u scanf aanroept, wordt u gedwongen de operator adres-of (& ) vóór uw variabelen te zetten.

scanf("%d", &mijnNummer);

Als u dat en-teken weglaat, crasht het programma. Waarom? Omdat scanf een geheugenadres verwacht, geen waarde. Als u dit gedrag begrijpt, wordt de logica achter hoe C omgaat met functieparameters ontgrendeld. Wanneer u een aanwijzer doorgeeft, verleent u een functie toestemming om in uw geheugen te reiken en gegevens rechtstreeks te herschrijven.

Het falen van pass-by-value

Om te begrijpen waarom aanwijzingen nodig zijn, moeten we kijken naar wat er gebeurt als ze ontbreken. Een veel voorkomende beginnersfout is het schrijven van een swap -functie die twee gehele waarden uitwisselt.

Hier is een naïeve implementatie die mislukt:

Voer deze code uit. De uitvoer toont 5 10 gevolgd door 5 10. De ruil heeft niet plaatsgevonden.

De reden is simpel. In C worden argumenten standaard op waarde doorgegeven. Wanneer swap(a, b) wordt aangeroepen, maakt het systeem lokale kopieën van a en b met de namen i en j. De functie wisselt de waarden van i en j perfect om. Maar wanneer de functie terugkeert, worden die lokale variabelen vernietigd. De originele ‘a’ en ‘b’ in ‘main’ blijven onaangetast.

De oplossing: pass-by-pointer

Om de oorspronkelijke variabelen te wijzigen heeft de functie toegang nodig tot hun werkelijke geheugenlocaties, en niet tot kopieën van hun waarden. Dit is waar aanwijzers voor functieparameters essentieel worden.

Hier is de gecorrigeerde implementatie:

De uitvoer is nu 5 10 gevolgd door 10 5. De ruil werkte.

Hoe pointer-dereferentie werkt

Het verschil ligt in wat er aan de functie wordt doorgegeven.

  1. De oproep: swap(&a, &b) geeft de adressen van a en b door.
  2. De parameters: De functiehandtekening void swap(int *i, int *j) declareert i en j als verwijzingen naar gehele getallen.
  3. De verbinding: Binnen swap bevat i het adres van a. j bevat het adres van b.
  4. De dereferentie: De verklaring *i = *j betekent “ga naar het geheugenadres opgeslagen in i, en schrijf de waarde gevonden op het geheugenadres opgeslagen in j erin.”

Stel je visueel twee vakken voor met de labels ‘a’ en ‘b’.
a bevat 5.
b bevat 10.
– ‘i’ is een briefje met het adres van vak ‘a’ erop geschreven.
j is een briefje met het adres van vak b erop geschreven.

Wanneer de code t = *i uitvoert, leest hij de noot i, gaat naar die locatie en leest de waarde 5. Het slaat 5 op in t. Vervolgens leest *i = *j de waarde uit vak b (dat is 10 ) en schrijft deze terug in vak a. De originele dozen zijn veranderd.

Het gevaar van het missen van het adres