Hallo, en welkom terug.
In deze lezing wil ik het hebben over de use case
voor pointers wanneer we ze gaan gebruiken hoe we ze gaan gebruiken We weten hoe we ze moeten maken.
verklaar ze en definieer ze.
We weten hoe we het adres van een bestaande variabele aan hen kunnen toewijzen met behulp van het adres van de operator.
En we weten hoe we ze kunnen de-refereren,
hoe we de waarde kunnen krijgen waarnaar de aanwijzer verwijst.
Hoe kunnen we ze nu daadwerkelijk gaan gebruiken.
Dus c biedt een aantal basisbewerkingen die u op pointers kunt uitvoeren.
U kunt een adres toewijzen aan een aanwijzer
waarover we al hebben geleerd.
Dit is een bestaande variabele waarbij de variabele een adres heeft.
En je kijkt gewoon naar het adres van die variabele door het adres van de operator te gebruiken,
en daar hebben we een punt voor. We kunnen ook een bestaande aanwijzer aan een andere aanwijzer toewijzen.
Dat zijn 2 manieren waarop u een adres aan een aanwijzer kunt toewijzen.
Het kan dus op zichzelf een arraynaam zijn.
We hebben het nog niet gehad over arrays, maar als je een verhoging aan een pointer
toewijst, hoef je alleen maar de naam op te geven. U hoeft niet eens het adres van de operator te gebruiken.
Tot nu toe hebben we ons alleen gericht op het gebruik van een bestaande variabele
en het doorgeven van het adres van de variabele zelf.
Maar de 3 manieren waarop u het kunt doen, worden daar genoemd.
U kunt ook een verwijzing naar een aanwijzer verwijderen. We hebben net geleerd dat je daar de
asterisk de indirecte-operator gebruikt.
Dit geeft u de waarde die is opgeslagen in de aanwijzer naar. De aanwijzer De waarde van de
aanwijzer, dat is een adres waarnaar het punt verwijst,
gebruik dat gewoon. U kunt ook een pointer-adres nemen.
Dit is het daadwerkelijke adres van de aanwijzer wanneer u de
aanwijzer maakt waar de aanwijzer zelf is opgeslagen.
U kunt ook het adres gebruiken dat ik op die aanwijzer heb.
En u kunt ook aanwijzerberekeningen uitvoeren. We gaan hier een aparte lezing over houden.
Hier kunt u de plus- en min-operatoren gebruiken om gehele
getallen aan een aanwijzer toe te voegen of om gehele getallen van een aanwijzer af te trekken.
En hierdoor kun je een specifieke notatie hebben en
kun je sneller in het geheugen rondspringen, vooral als je arrays gebruikt.
Dus wat je meestal doet, is wanneer je een geheel
getal aan een aanwijzer toevoegt
met behulp van de
plus-operator, het adres van die aanwijzer gewoon zoveel bytes instelt.
Als je een
getal van een aanwijzer aftrekt, wordt
dat adres in min een bepaald aantal bytes gezet.
Je kunt de verlaging ook met één verhogen, en
je zult zien dat dit heel gebruikelijk is wanneer we het in arrays gebruiken.
Dus als u zich in een array bevindt en u wilt naar het volgende element gaan in plaats van de index te
gebruiken, kunt u een aanwijzer gebruiken en deze met één verhogen.
Als u naar het vorige element wilt gaan in plaats van een index te gebruiken,
kunt u deze met één punt verlagen.
Dus pointer-rekenkunde, we gaan het exclusief hebben over, maar dat is
iets dat je met pointers kunt doen.
En nogmaals, het is een specifieke notatie waarmee je snel in het
geheugen kunt bewegen, efficiënter
kunt zijn.
Je kunt ook het verschil tussen 2 wijzers vinden.
Dus als je 2 pointers hebt en de elementen bevinden zich in dezelfde array, wil
je misschien weten hoe ver ze van elkaar
verwijderd zijn, de elementen, je kunt ze minnen.
Dit zou het verschil zijn
van 2 wijzers en. Dus als je index 5 bent en dan had
je een pointer point in index 5, je had nog een pointer point die naar index
15 wijst, je zou ze kunnen minen en
dat zou je geven
hoeveel elementen ze weg zijn, want het zou zijn het hexadecimale adres minus het andere
hexadecimale adres uitgaande van de array in het continue geheugen die
het is, het zal weergeven hoe ver ze van elkaar verwijderd zijn.
U kunt relationele operatoren gebruiken om de waarden van 2 pointers te vergelijken.
Pointers moeten van hetzelfde type zijn. Dus als ze allebei naar gehele getallen wijzen, moeten ze
allebei van hetzelfde type zijn.
Dit gaat u alleen vertellen of de adressen groter of kleiner zijn dan.
Nogmaals, je zou kunnen identificeren in welk deel van de array je je bevindt.
Er zijn ook 2 vormen van aftrekken.
Dus ik heb net gesproken over
aftrekken, waarbij je één aanwijzer kunt nemen en deze kunt aftrekken van een
andere, waardoor je
een aanwijzer krijgt of je kunt één aanwijzer van
een geheel getal aftrekken, waardoor je een aanwijzer krijgt.
Dus trek de ene aanwijzer van de andere af om een geheel getal te krijgen of om
een geheel getal van een aanwijzer af te trekken om een aanwijzer te krijgen. Dat zijn de 2 gevallen.
Dus we zullen in gedachten houden dat we nog wat voorbeelden zullen doornemen.
Wees voorzichtig wanneer u het verhogen of verlagen van aanwijzers gebruikt en ervoor zorgt
dat de array buiten de grenzen valt. Dus de meeste dingen die je
doet met aanwijzerberekeningen, is wanneer je op arrays werkt.
Want nogmaals, het stelt je in staat om snel te bewegen, het is een simpele syntax.
Maar onthoud dat de arrays een fout buiten de grenzen hebben.
Dus als je te ver incrementeert, ga je buiten
de grenzen in de array. Als je te ver verlaagt,
krijg je een ondergrens, je gaat naar een negatief getal.
De computer zelf houdt niet bij of een aanwijzer nog steeds naar een array-element verwijst.
Dus als je het punt van rekenen op arrays gebruikt, moet je voorzichtig zijn.
Als u pointers wilt gebruiken in uitdrukkingen, kunt u dat ook doen.
Dus we hebben hier iets eerder over gesproken, en we hebben de verwijzing naar de aanwijzer verwijderd en er
15 aan toegevoegd. Ik denk dat we er 20 hebben.
Dus de waarde van pi pointer kan worden gebruikt in rekenkundige uitdrukkingen.
Dus als een variabele is gedefinieerd als van het type pointer naar geheel getal, dan wordt
deze geëvalueerd met behulp van de regels van de rekenkunde met gehele getallen.
En dat hebben we met dereferentie laten zien. Dus als je een
variabele hebt en je hebt een aanwijzer, initialiseer deze dan naar null, dan onderteken je
je aanwijzer het adres van die variabele. Je kunt dan gewoon zeggen ster pgetal plus is gelijk aan 25.
Onthoud dat star pnumber de waarde krijgt waarnaar wordt verwezen.
Dus wat dit doet, is dat het zegt dat de waarde van pgetal
gelijk is aan de waarde pgetal plus 25.
Dus de waarde wordt gelijk aan 35.
Dit verandert niet waar het naar verwijst omdat we een asterisk gebruiken, dus het verandert niet
het adres waarnaar we verwijzen, het verandert het
adres zelf niet omdat we het adres van de operator niet hebben.
We veranderen de waarde waarnaar het verwijst.
Dus door de waarde van de getalvariabele met 25 te verhogen, geeft de ster aan dat
je de inhoud vraagt waarnaar de variabele met de naam pnumber verwijst.
Als een aanwijzer naar variabele x wijst,
is die aanwijzer gedefinieerd als een aanwijzer naar hetzelfde gegevenstype als x.
Dus als u een eindaanwijzer een zwevende aanwijzer maakt, kunt
u alleen een adres hebben
van een gegevenstype dat float of int is, afhankelijk van welke u hebt gedeclareerd.
Het gebruik van de indirecte-operator in een uitdrukking
is dus identiek aan het gebruik van x in dezelfde uitdrukking.
En dat is alles wat het zegt, als je een float gebruikt of je hebt
een int en je gebruikt de indirection-operator, je verwijst ernaar, je kunt doen
wat je kunt als je een float erin had, waar het ook naar verwijst.
Een variabele die is gedefinieerd als een aanwijzer naar een int kan het adres van elke
variabele van het type in opslaan, dat weten we.
Dus hier is de int-waarde gelijk aan 999, we kunnen die int toewijzen aan pgetal
zolang pgetal een aanwijzer is naar een int, en dan kunnen
we er aan toevoegen.
De instructie werkt met de nieuwe variabelewaarde
en de nieuwe inhoudswaarde is 1024.
Pnummer wijst naar waarde, het
adres van waarde. Dus als u de aanwijzer verandert
waar deze naar verwijst, verandert u de waarde van deze variabele.
Dus onthoud dat dit het concept is van het veranderen van een variabele op één plek
in de aanwijzer en je verandert het in meerdere variabelen.
Een aanwijzer kan het adres van elke variabele van het juiste type bevatten.
U kunt dus één aanwijzervariabele gebruiken om de waarden van veel verschillende variabelen te wijzigen als
er ints of doubles of floats zijn. Zolang ze van het type zijn dat compatibel is met
het aanwijzertype, kunt u die waarde wijzigen. U kunt de pnumbers-waarde niet
wijzigen als pnumber naar een float wijst en de waarde een
geheel getal is. Dat zou je niet kunnen. Je zou een compileerfout hebben.
Hier nog een voorbeeld. Hier laten we u zien
hoe u het adres van sommige variabelen kunt krijgen. Dus hier in dit hoofdgedeelte doen
we wat rekenkundige
berekeningen voor de eigenlijke uitdrukkingen.
Dus we doen niets op array, dus we verhogen of verlagen daarin
geen pointers. Dus we verlagen de waarden. Dus we hebben 2
lange typen num1 en num2 en dan hebben we een aanwijzer van het type long, we initialiseren deze naar null.
We wijzen het adres van num1 toe aan onze pointer pnum.
En dan kennen we de waarde van pnum toe aan
L, dus dat betekent dat num1 nu 2l wordt.
Als we num2 verhogen, heeft num2 nog niets
gedaan.
Dus de waarde van pnum is 2l, dat betekent dat de waarde van num1 2l is.
L is slechts het achtervoegsel om aan te geven dat het lang is.
Als we nu de lange num2-waarde verhogen, is
het 0l, het wordt 1l.
Als we zeggen dat num2 plus gelijk
is aan ster pnum, pnum is 2l, dus het
wordt 1l plus 2l, num2 wordt nu gelijk aan 3l.
En als we het adres van num2 aan pnum toewijzen, wordt
pnum nu gelijk aan het adres van num2.
Dus als we pnum verhogen
waar we naar verwijzen, hebben we nu 4l.
En we zullen dit bekijken in de binnenkant van koude blokken,
maar ik begeleid je er doorheen. Num1 wordt gelijk aan 2l.
Num2 zal gelijk zijn aan het punt dat
naar pnum wijst.
Pnum is 3l, dus ik denk dat het 3l wordt.
Pnum wordt 3l, en dan wordt pneum plus
num2 6l.
Dus laten we kijken of ik gelijk heb, doorloop dit in codeblokken.
Dus hier zijn we in codeblokken, probeerden dit met de hand te doorlopen, maar
nu willen we zien of we gelijk hebben. Laten we de debugger gebruiken.
We plaatsen dit hier en we zullen zien hoe waarden veranderen terwijl we door het programma gaan.
Dus laten we dit bouwen, en laten we het debuggen.
Deze gaat starten en stopt bij lijn 10.
En als we ons kijkvenster naar voren halen, wat
we kunnen doen door debuggen in Windows Watches, Watches, kunnen we de
waarden zien terwijl ze bezig zijn. Dus nu is
num1 nul, num2 is nul, pnum wijst naar nul.
Daarom is het 0x0, omdat
we weten dat null 0 vertegenwoordigt in pgetal.
En dat kunnen we gebruiken als we het vergelijken in if-statements.
Dus nadat we regel 10 hebben uitgevoerd, zou pnum nu het adres num1 moeten hebben.
Dus laten we gewoon overstappen.
Nu heeft pnum een actueel adres 0x60ff08.
Nadat we regel 11 hebben uitgevoerd, gaan we zeggen dat de waarde van pnum gelijk is aan 2l, en we
zullen daarvoor niets in het kijkvenster zien. Maar laten we doorgaan en het uitvoeren, pnum
heeft nog steeds hetzelfde adres.
Num1 is nu echter veranderd omdat pnum het adres van
num1 had, en we hebben het veranderd.
Dus nu is nummer 1 2. Nu gaan we in regel 12 num2 verhogen.
Dus num2 wordt gewoon 1l.
Het wordt 1. Het adres van pnum is nog steeds hetzelfde.
Nu gaan we aan num2 toevoegen wat
pnum ook was. Pnum onthoud wijst
naar num1, dus num2 zou 3 moeten zijn.
Dan gaan we naar 14, num2 is 3, num1 is nog steeds 2.
Nu op regel 15, gaan we
pnum een nieuw adres van num2 toewijzen. Dus hierna
zullen we niet langer 0x60ff08 zijn.
We worden 060ff04.
Dus als we nu de waarde verhogen waar de pnum naar verwijst, is nummer
2 en nummer 2 is 3, nummer 2 zou nu 4 moeten zijn.
En we zien dat het 4 is.
Nu gaan we al deze waarden afdrukken en je zult zien dat de waarde van num1
2 moet zijn.
De waarde van num2 moet 4 zijn.
Pnum wijst naar num2, dus dat zou nog 4 moeten zijn.
En dan gaan we zeggen dat de waarde van pnum die 4 plus is,
num2 die 4 is, 8 zou moeten zijn.
Dus misschien was ik er met 6 af.
Dus nu zullen we dat niet kunnen zien in het uitkijkvenster. Dus laten we het
gewoon spelen en de uitvoer zien als printf-statements. We zouden 2448 moeten zien.
Dus laten we dit nu uitvoeren in niet-debug-modus,
en we zien 2 4 4 8.
Dus daar gaan we. Ik hoop dat dat logisch was.
Laten we teruggaan en onze discussie voortzetten.
Dus hoe zit het met wanneer we input ontvangen, hoe kunnen we pointers op die manier gebruiken.
Als we tot nu toe scanf gebruiken om waarden in te voeren, moeten we de ampersand-operator
gebruiken wanneer we een inter- of float-gegevenstype hebben. De enige keer dat we het hebben, is
wanneer we een tekenreeks hadden en de reden daarvoor is omdat het teken
a eigenlijk een tekenaanwijzer is waar we het over gaan hebben.
Maar als we scanf gebruiken om waarden in te voeren en we gebruiken
ze op normale gegevenstypen die geen tekenarrays zijn, hebben we altijd deze add- of sub-operator moeten gebruiken.
En de reden daarvoor is dat scanf's tweede argument een pointer is.
Dus we moeten het een adres sturen. Pointers hebben alleen waarden van adressen.
Dus als je een pointer hebt die al een adres bevat, kun je de pointernaam gebruiken als argument voor scanf.
Dus nu hoef je de ampersand-operator niet te gebruiken als je daadwerkelijk een aanwijzer
hebt gemaakt, omdat het tweede argument voor de scanf een aanwijzer is en je
dus gewoon de aanwijzernaam kunt zeggen.
Als we in het verleden een waarde in waarde
wilden opslaan, zouden we
de ampersand-waarde in het scanf-tweede argument hebben.
Maar als we een aanwijzer hebben die we maken en die al
naar een adres verwijst, zoals in dit
voorbeeld, dan hoeven we, als we scanf gebruiken, alleen maar de naam van de waarde te zeggen,
de naam van de aanwijzer.
Dus hier is een geval waarin we een geheel getal hebben, maar
we hoeven geen ampersand te gebruiken omdat we een aanwijzer naar een geheel getal hebben.
We zeggen gewoon procent d, p-waarde.
Er zijn dus andere momenten waarop u normale
namen van variabelen kunt doorgeven aan scanf naast tekenreeksen als u
een aanwijzer hebt.
Je kunt ook achteraf afdrukken wat ze hebben ingevoerd en je zult
merken dat die waarde daadwerkelijk wordt gewijzigd in wat ze hebben
ingevoerd, omdat we naar dat adres verwijzen.
Testen op nul.
Er is één regel die je in je geheugen moet branden. Dit is heel erg belangrijk.
We hebben het gehad over dereferentie, maar wat gebeurt er als je
een onbedoelde aanwijzer derefereert, een aanwijzer die naar niets
wijst of een aanwijzer waaraan geen geheugen is toegewezen.
Dus wat als we zoiets doen. We declareren een pointer, maar
we hebben deze nooit echt geïnitialiseerd, en dan proberen we deze toe te wijzen.
We de-refereren en toewijzen, dat is een grote fout.
Dus de tweede regel betekent in feite dat
je de waarde 5 wilt opslaan op de locatie
waarnaar pt verwijst, maar pt verwijst nergens naar omdat het niet is geïnitialiseerd.
Dus pt krijgt nu een willekeurige waarde.
Er is dus geen idee waar 5 zal worden geplaatst, het kan overal in het geheugen worden geplaatst.
Dit kan ongevaarlijk zijn. Het kan
bestaande gegevens of bestaande toestandsvariabelen in uw programma overschatten.
Het kan ervoor zorgen dat het programma crasht. Het is erg problematisch.
Dus wanneer u een aanwijzer maakt en u geheugen toewijst om de aanwijzer zelf op te slaan, wijst deze
geen geheugen toe om de gegevens op te slaan.
Dus door instar pt te zeggen, toegewezen
geheugen voor de aanwijzer, maar het wees geen
geheugen toe voor wat voor de waarde van
de aanwijzer, het adres. Onthoud dat pointers adressen bevatten.
Het creëerde de aanwijzer, maar het creëerde geen geheugen voor waar het naar verwijst.
Je kunt er dus niet naar verwijzen.
Het wijst dus geen geheugen toe om de gegevens op te slaan.
Voordat u een aanwijzer gebruikt, moet deze een geheugenlocatie toegewezen krijgen die al is toegewezen
of u moet dynamische geheugentoewijzing gebruiken met malloc waar we het over zullen hebben.
U wijst dus ofwel het adres van een bestaande variabele toe aan
de aanwijzer of u gebruikt malloc wat dynamische geheugentoewijzing is.
Maar onthoud dat wanneer u een aanwijzer gebruikt als u deze hebt gemaakt en
deze null is, u deze vooraf op null wilt controleren,
daar zullen we het zo over hebben. Maar als u een aanwijzer hebt
gemaakt die niet is geïnitialiseerd, wijs er dan niets aan toe,
tenzij deze verwijst naar een andere variabele die op die manier is geïnitialiseerd of als er geheugen is toegewezen.
Dus dit is waar null in het spel komt.
Je kunt eigenlijk testen op null om er zeker
van te zijn dat je geen dereferentiefout hebt. Zorg ervoor dat uw programma niet crasht.
Dus we weten al dat null in feite naar
niets verwijst en we zouden al onze variabelen moeten initialiseren,
onze verwijzingen naar null.
Zoiets moeten we dus altijd doen.
Null is een speciaal symbool in c dat de aanwijzer vertegenwoordigt die gelijk is
aan nul met gewone getallen.
Het onderstaande stelt ook een aanwijzer in op null met nul.
Dus we kunnen ook, als we het niet willen doorgeven of het niet willen toewijzen aan null, we gewoon 0 kunnen zeggen
en dat is het equivalent van zeggen dat we naar niets wijzen.
Dus omdat null het equivalent is van 0,
kun je, als je wilt testen of de p-waarde null is, zoiets doen
als expliciete tests gebruiken. Je kunt zeggen dat pointer gelijk is aan nul.
En als de aanwijzer gelijk is aan nul, wat betekent dat het
nul is, dan kun je echt iets doen.
Dus als het niet nul of niet null is, is het een waar of een
andere waarde, dat is een manier om te controleren op crashes.
U zorgt ervoor dat voordat u daadwerkelijk iets probeert te
derefereren, dit u zal vertellen of er al dan niet geheugen aan is toegewezen.
U wilt dus controleren op null voordat u een verwijzing naar een aanwijzer verwijdert.
En je doet dit vaak in
functies omdat functies pointers als parameters gebruiken.
En als de
beller slechte gegevens doorgeeft of een aanwijzer doorgeeft die geen geheugen heeft
toegewezen, kan uw code crashen. Dus wat u wilt doen, is ervoor zorgen
dat de beller een geldig adres heeft, zodat u het op nul kunt controleren.
Kortom, wat dit betekent om altijd deze if-controles te hebben
om geen p-waarde of geen aanwijzer te zeggen.
En als het geen aanwijzer is, kun je het dereferenteren.
We hebben het veel over aanwijzingen. We hebben nogal wat besproken.
Ik weet zeker dat het een beetje overweldigend wordt. Misschien wil je een pauze nemen
en de vorige lezingen doornemen en proberen dit concept echt in je hoofd te synchroniseren.
Pointers bevatten alleen adressen.
Maar er zijn 3 delen, dus het kan problematisch worden.
Maar blijf positief. Blijf bij me en ik weet
dat het verwarrend is.
We hebben het gehad over het werken met adressen.
We hebben het gehad over werken met waarden. We hebben het gehad over het werken met de
aanwijzer zelf, en we hebben het gehad over het werken met variabelen die naar de aanwijzer wijzen.
Dus er zijn al deze dingen
die je moet onthouden, en het kan heel erg overweldigend en frustrerend zijn.
En het is altijd moeilijk om erachter te komen wat er aan de hand is en het zal veel oefening vergen.
De beste manier om dit concept en alles wat we tot nu toe hebben
gesproken te begrijpen, is door
te oefenen, korte programma's te schrijven die alle concepten gebruiken die ik heb genoemd.
Dus schrijf een programma dat de
waarden krijgt met behulp van een aanwijzer, dit zou misschien
de indirecte-operator zijn, dereferentie. Schrijf een programma dat waarden verandert met behulp van pointers.
Dus dit zou dereferentie zijn, het verkrijgen van de waarden met behulp van aanwijzers zou gewoon de
naam zijn van de aanwijzer die het adres zou zijn. Adressen afdrukken, we hebben al die syntaxis doorgenomen.
Oefen deze dingen keer op keer, zo word je er goed in.
Je moet je zelfvertrouwen vergroten en je moet deze concepten in detail bestuderen om ze
onder de knie te krijgen.
We hebben nog veel meer om over aanwijzingen te praten, maar dit kan een tijd zijn om gewoon afstand te nemen en door
te nemen waar we het tot nu toe over hebben gehad, zodat het in je hoofd wordt geboord.
Dank u.