Hallo, en welkom terug.
In deze lezing wil ik het hebben over een concept dat pass by reference wordt genoemd.
Toen we voor het eerst over pointers begonnen te praten, noemde ik een van de voordelen dat
je niet zo veel globale variabelen hoeft te gebruiken.
Omdat wanneer u een aanwijzer naar een
functie doorgeeft, de functies die parameter kunnen gebruiken. En wanneer het die parameter wijzigt, worden de
gegevens buiten de functie gewijzigd.
Dit is dus een waardevol, waardevol concept.
We gaan het hier over hebben. Dit is meer een concept. C gebruikt dit eigenlijk niet.
En ik ga je laten zien hoe en wat
voorbeelden geven hoe dit werkt.
Dus er is dit concept van pass-by-waarde. Dit heeft te maken met functies.
We hadden het over het doorgeven van gegevens aan een functie, maar hoe wordt het eigenlijk doorgegeven
in termen van de taal in de compiler.
Er is dus een concept van pass-by-waarde. En dit is waar
we het tot nu toe over hadden. Telkens wanneer we de functie aanroepen
naast de scanf-functie, maar om de andere keer dat we de functie
aanroepen, werd wanneer u die gegevens binnen de functie aanpaste, deze
niet gewijzigd buiten de functie.
Dus we hadden het over lokale variabelen, dat is een ander concept.
Maar wanneer u gegevens aan een functie doorgeeft, kunt u deze op twee manieren doorgeven.
U kunt het doorgeven op waarde, u kunt het doorgeven door middel van verwijzing.
C gaat uitsluitend voorbij aan waarde en dat geldt
ook voor java,
alle passeren door waarde. Maar het simuleert pass-by-referentie omdat
u adressen kopieert.
En hoewel dit concept pass
by reference niet specifiek door c wordt gebruikt,
simuleert het het. Om te begrijpen wat pass by reference
betekent en waarom dat belangrijk is, gaan we daarover praten.
Maar pass-by-waarde is wanneer een functie de werkelijke waarde van een argument kopieert
naar de formele parameter van de functie.
En dit is de reden waarom als je een geheel
getal, een float of een double hebt en je geeft dat door als argument aan
een functie, die eigenlijke variabele niet buiten de functie wordt gewijzigd omdat hij gekopieerd is.
Wijzigingen in de parameter binnen de functie hebben dus geen effect op het argument.
Het argument dat wordt doorgegeven, wordt niet gewijzigd.
Het gedraagt zich dus bijna als een lokale variabele omdat het een kopie is.
Hoe het eigenlijk onder de motorkap gebeurt, is dat het wordt gekopieerd en doorgegeven aan de functie.
C-programma gebruikt call by value om argumenten door te geven.
Alles wordt genoemd door waarde pass door waarde.
Deze termen worden door elkaar gebruikt.
Dus nogmaals, dit betekent dat de code binnen een functie de argumenten die worden gebruikt om de functie aan te roepen, niet kan veranderen.
Er zijn geen wijzigingen in de waarden, hoewel ze binnen de functie zijn gewijzigd.
Het lijkt alsof het lokale variabelen zijn.
En dat is de reden waarom eerder tot dit
punt, toen u globale gegevens moest maken als u de gegevens van de ene functie naar de andere wilde delen.
En zo werkt c.
Maar wat gebeurt er als je daadwerkelijk een kopie
van een adres doorgeeft. Dan kan het passeren door verwijzing nabootsen.
Maar hier is een voorbeeld van hoe we pass-by-waarde hebben gebruikt, het wordt hier heel mooi gedemonstreerd.
Deze swap-routine wordt vaak gebruikt om pass-by-waarde te demonstreren,
omdat het een temp creëert en de parameters verwisselt die
de argumenten worden doorgegeven.
Dus als we een functie hebben met de naam swap die twee gehele getallen
nodig heeft, maken we een lokale variabele temp.
Als we aan de parameter x toewijzen aan temp, wordt
temp gelijk aan x. Als we zeggen dat x gelijk is aan
y, wordt y nu gelijk aan x. Als we zeggen dat y gelijk is aan
temp, wordt y gelijk aan temp.
Maar wanneer deze functie wordt aangeroepen door die waarden door te geven,
zullen x en y lokaal zijn voor deze functie.
Die variabelen worden niet gewijzigd buiten deze functie.
En deze functie demonstreert het erg handig omdat we toewijzen
aan y en we toewijzen aan x.
En x en y zijn lokaal voor deze functie omdat we de
waarde doorgeven, ze worden niet gewijzigd buiten deze functie en daarom moeten we globale variabelen gebruiken.
Maar het zijn gehele getallen. Het zijn twee gehele getallen x en y. Het zijn geen adressen,
het zijn gehele getallen en dat is significant.
Dus als we swap
noemen en we zien hoe dit eruit ziet, zul
je merken dat de waarden niet veranderen.
Dus als we een variabele maken met de naam 100 b
met 200 en we printen de variabelen uit voordat we ruilen,
100 en 200, dan noemen we swap,
de variabelen worden niet gewijzigd nadat
we ze opnieuw hebben uitgeprint.
Laten we dit dus bekijken in codeblokken en dit zal de pass-by-waarde demonstreren.
Dus hier is ons voorbeeld. We hebben onze wisselroutine.
We verwisselen waarden van gegevens die door x en y zijn gegaan.
We noemen het met 100 200.
We gaan uitprinten voordat we de functie aanroepen.
We gaan daarna uitprinten.
En wat je zult opvallen, is dat de variabelen a en b nooit veranderen.
En de reden hiervoor is omdat we waarde doorgeven.
Dus als ik dit programma uitvoer,
kunnen we zien dat vóór het verwisselen de waarde van a 100 was nadat je de waarde van a had
verwisseld 100 en hetzelfde voor b 200 en 200.
En de reden hiervoor is dat we voorbij zijn aan waarde. Als we de referentie zouden doorgeven,
zouden die variabelen a en b veranderen na de aanroep om te wisselen.
Hoe zit het als we dezelfde techniek gebruiken als pass-by-value, maar we
kopiëren pointers, wat denk je dat er gaat gebeuren?
Pointers en functies gaan dus goed samen.
U kunt een aanwijzer als argument aan een
functie doorgeven en u kunt een functie ook een aanwijzer als resultaat laten retourneren.
We gaan ook laten zien hoe je dat kunt doen.
Maar pass by reference kopieert het adres van een argument naar de formele parameter.
Het adres wordt gebruikt om toegang te krijgen tot het daadwerkelijke argument dat in de aanroep wordt gebruikt.
Dit betekent dus dat de wijzigingen die in de parameter in
de functie zijn aangebracht, van invloed zijn op het argument in de aanroep.
En hoewel het technisch gezien niet onder de motorkap wordt doorgegeven
via referentie, bootst of simuleert het pass-by-referentie.
We kopiëren het adres. Als je het adres kopieert,
heb je een nieuw adres en geheugen voor die waarde het adres.
Maar als u probeert toe te wijzen aan dat adres, wordt het toegewezen aan het adres.
Dus ook al wordt het doorgegeven door waarde, het kopieert.
En als u een gewoon geheel getal kopieert, brengt u geen wijzigingen aan. Als u een adres kopieert, bevindt het adres
zich in het geheugen, dus wanneer u wijzigingen aanbrengt, brengt u wijzigingen aan in dat adres.
Dus om de waarde via referentie
door te geven, worden argumentaanwijzers doorgegeven aan de functies, net als elke andere waarde.
U moet de functieparameters declareren als aanwijzertypes met de asterisk.
Veranderingen binnen de functie worden ook buiten de functie weerspiegeld.
U hoeft niet zo veel globale variabelen te gebruiken.
In tegenstelling tot een aanroep op waarde waarbij de wijzigingen niet buiten de functie worden weergegeven.
We kopiëren nog steeds, we geven nog steeds waarde door, het is gewoon de waarde van een kopie van het adres.
Dit is dus een belangrijk concept om te begrijpen.
Wanneer we nu onze swap-functie maken,
gaan we deze maken met de verklaring in de
functie als sterretje, ster en ster.
Dat wil zeggen dat deze functie pointers nodig heeft.
Wanneer we nu binnen deze functie toewijzen, moeten
we de indirectie-operator gebruiken om te derefereren omdat we
de waarden willen toewijzen. We gaan de waarde toewijzen
die x die x naar de temp wijst.
We gaan de waarde van x punten toekennen aan de waarde
waar y naar wijst en dan gaan we de waarde toewijzen waar y naar wijst, aan temp.
Temp is een geheel getal, dus we hoeven er niet naar te verwijzen.
Als we het nu
aanroepen met a100 en b200 door a
en b door te geven, zijn a en b geen pointers, dus we moeten het
adres doorgeven omdat de functie pointers nodig heeft.
Wanneer je een functie hebt die pointers nodig heeft en je declareert geen pointer, dan
moet je het adres van de operator gebruiken en het is hetzelfde als hoe we scanf gebruiken.
Maar nu zul je merken dat wanneer we
dit aanroepen na de oproep om de variabelen a en b te
verwisselen, ze zullen worden verwisseld. A wordt 200 b wordt 100.
Laten we nu eens kijken naar dit voorbeeld met onze swap-methodewijziging naar pointers in codeblokken.
We zitten in codeblokken. We hebben de swap-functie aangepast om pointers te gebruiken.
Dus we moeten ze negeren wanneer we ze toewijzen.
We geven nu ook het adres van a en b door omdat dit nu gehele getallen zijn
en de swap nu pointers nodig heeft. Dus als we dit uitvoeren, zullen
we zien dat de oproep en daarna nu worden gewijzigd.
Dus voordat we swap noemen is a gelijk aan 100 nadat we swap noemen is 200.
Voordat we ruil voor b noemen, is het 200. Daarna is het 100.
We kunnen dus de waarden van variabelen binnen de functie wijzigen
omdat we een kopie van het adres maken. Heel, heel belangrijk, en een van
de grote voordelen van pointers.
Dus laten we de syntaxis samenvatten. Dat heb ik al gedaan, maar laten we er dieper op ingaan.
U kunt twee soorten informatie over een variabele doorgeven aan een functie.
U kunt de waarde van x
verzenden en de functie moet worden gedeclareerd met hetzelfde type als x.
We weten dat. Telkens wanneer we gegevens doorgeven
aan een functie, moeten we dezelfde typen hebben wanneer we deze aanroepen.
En hier hebben we int function1 om het aan te roepen en het is gedefinieerd als een int num.
Dus als we de waarde van x in de functie verzenden, moeten ze met hetzelfde type worden gedeclareerd.
En als je dan daadwerkelijk een adres van x wilt aanroepen,
moet de functiedefinitie een verwijzing naar het juiste type bevatten.
Dus wanneer u aanwijzers gebruikt, moet u ervoor zorgen dat als u
gegevens doorgeeft en die gegevens geen aanwijzer zijn, u het adres ervan moet krijgen.
Wat dit samenvat, is dat als je een functie definieert die geen aanwijzer nodig heeft, je
deze gewoon kunt aanroepen en de gegevens kunt doorgeven.
Zorg ervoor dat het geen aanwijzer is.
Als u een functie heeft die wel een asterisk-aanwijzer nodig
heeft, moet u deze
aanroepen met de operator toevoegen of sub wanneer u deze aanroept.
U moet het adres doorgeven.
Dat is de syntaxis.
Nu kunt u ook een functieparameter kwalificeren met behulp van het constante trefwoord.
Dit geeft aan dat de functie het argument dat voor deze parameter wordt doorgegeven, als een constante zal behandelen.
Het is alleen nuttig als de parameter een aanwijzer is.
Want als je waarde passeert en je geeft geen pointers door, maakt het niet uit, want het heeft geen
invloed op de verandering aan de buitenkant van de functie, dus waarom zou
je er een constante van maken, wat maakt het uit als je het verandert .
De enige reden waarom je een aanwijzer constant maakt, is omdat je niet wilt
dat de waarden buiten de functie veranderen.
En dus kun je het constante sleutelwoord toepassen op een parameter die een pointer
is om aan te geven dat de functie de waarde waarnaar het argument verwijst niet zal veranderen.
Erg belangrijk.
Dus in dit voorbeeld hebben we een functie voor het verzenden van berichten. Er is een
p-berichtaanwijzer nodig.
We plaatsen het constante sleutelwoord voor de char-ster.
Dus dit type parameter p-bericht is een verwijzing naar een constant teken.
Het is de tekenwaarde die constant is, niet het adres.
Dus wat we in dit geval doen, is dat de aanwijzer waarnaar wordt verwezen niet kan veranderen.
We kunnen het adres wijzigen, maar we kunnen niet veranderen wat het naar de waarde verwijst.
De syntaxis is vergelijkbaar met wanneer we constanten op andere pointers maken.
Het constante sleutelwoord is dat dit het eerste is dat wordt weergegeven en dat u de waarde niet kunt wijzigen.
Nu zou je kunnen specificeren dat de aanwijzer zelf constant
is, maar dit heeft weinig zin omdat het adres door waarde wordt doorgegeven.
U kunt de renderpointer
niet wijzigen in de aanroepende functie. Dus dit is alleen als je probeert het zo te maken dat het adres niet kan
worden gewijzigd, wat heeft het voor zin omdat het door waarde wordt doorgegeven. Dus je maakt eigenlijk
een nieuwe geheugenlocatie om dat
specifieke adres vast te houden. Dus als je het verandert, wat maakt het uit dat het het aan de buitenkant niet zal veranderen.
Je wilt alleen in staat zijn om de parameter een
constante te maken, zodat je de waarde van waar het naar verwijst niet verandert,
je kunt de originele
aanwijzer en de aanroepende functie sowieso niet veranderen omdat het wordt doorgegeven door de
waarde die door de kopie wordt doorgegeven.
De compiler weet dat een argument dat verwijst naar constante
gegevens veilig is, dus dit heeft voordelen. U kunt niet per ongeluk wijzigen waarnaar de waarde verwijst.
U kunt dit dus opnieuw doen als u niet wilt dat de wijzigingen aan de buitenkant van de functie worden weergegeven.
Als u een pointer naar constante gegevens doorgeeft als argument voor een parameter,
dan moet de parameter worden gebruikt zoals in het bovenstaande.
Wanneer je de functie aanroept en deze doorgeeft aan een constante,
dan moet je de functiedeclaratie ook een constante karakteraanwijzer laten nemen, net
als normale andere aanwijzers die constanten zijn.
Ze moeten worden gedefinieerd en de definities moeten overeenkomen met het prototype.
Pointers van een functie retourneren.
Het retourneren van een aanwijzer van een functie is een bijzonder krachtige mogelijkheid.
Het biedt u een manier om niet slechts één waarde te retourneren, maar een hele reeks waarden.
Dus nogmaals, een van de andere voordelen die ik
noemde over pointers, is dat je nu meer gegevens uit een functie kunt retourneren.
In het verleden kunt u slechts één waarde retourneren.
Maar met een aanwijzer omdat een aanwijzer zou kunnen
wijzen naar een structuur waar we het nog niet over hebben gehad of zelfs
andere dingen, kun je meerdere
waarden retourneren. Dus we weten hoe we aanwijzers naar functies moeten doorgeven, nu
willen we het hebben over terugkerende aanwijzers.
Je zou een functie moeten declareren die een pointer retourneert. De functiedeclaratie moet dus overeenkomen.
Het is heel gemakkelijk om dat te doen. U zegt gewoon dat u de asterisk
gebruikt wanneer u de functie declareert of definieert en het retourtype voor die aanwijzer heeft waarnaar deze verwijst.
Wees dus voorzichtig, hoewel er specifieke gevaren zijn met betrekking tot het retourneren van een aanwijzer.
Gebruik lokale variabelen om interferentie met de variabele waarnaar het argument verwijst te voorkomen.
Het is enigszins problematisch wanneer u pointers retourneert, want als u die pointer binnen de functie wijzigt
en vervolgens retourneert, kan het iets zijn
dat u niet van plan bent te doen.
Gebruik dus altijd lokale variabelen als je geen invloed wilt hebben op een variabele
waar je argument naar verwijst.
En dus beschreef deze lezing hoe
je pointers naar functies kunt
doorgeven en hoe je pointers van functies kunt retourneren.
En door dit mechanisme te gebruiken om verwijzingen naar
een functie door te geven, demonstreert of bootst het
pass-by-referentie na, omdat je een adres kopieert.
En als je een adres kopieert als je naar dat adres schrijft, dan
update je alles wat naar
dat adres verwijst, wat in feite betekent dat je de waarde van de
gegevens binnen de functie verandert, het zal het buiten de functie weerspiegelen.
We gebruiken de swap-routine om dat aan te tonen.
Dit is een zeer krachtig concept. En je wilt pass by reference nabootsen,
je kunt daar pointers voor gebruiken en dat wil je doen als je dingen buiten de functie wilt veranderen.
Dank u.