Hallo, en welkom terug.
In deze lezing wil ik het hebben over het gebruik van aanwijzers en structuren,
en hoe deze verband houden.
We kunnen elementen in een structuur een
aanwijzer laten zijn, en dan kunnen we onze structuren zelf ook aanwijzers maken.
Twee zeer bruikbare concepten.
Dus structuur is hier belangrijk. c staat voor pointers twee structuren toe.
Dus wanneer we een variabele van het type structuur maken, kunnen we
deze als een aanwijzer maken.
Aanwijzers naar structuren zijn gemakkelijker te manipuleren dan structuren zelf.
Dus nogmaals, het is een soort notatie,
maakt dingen een stuk eenvoudiger en het is ook efficiënter.
In sommige oudere implementaties van de taal
c kan een structuur
niet als argument aan een functie worden doorgegeven, maar we
weten dat een aanwijzer dat wel kan. Dit is dus nog een reden
waarom je een structuur als aanwijzer wilt hebben wanneer je
het declareert, want dan kun je het doorgeven in oudere versies van
c, je kunt het als argument doorgeven aan een functie.
Zelfs als u een structuur als argument kunt doorgeven, is
het doorgeven van een aanwijzer efficiënter.
We weten dat dat efficiënter is. We hebben hier in het verleden over
gesproken hoe het doorgeven van belangrijke zaken efficiënter kan.
In dit geval is het zelfs
nog efficiënter, want als je een hele structuur doorgeeft, als de
structuur groot is en veel elementen bevat, kopieer
je alle elementen in de structuur naar die parameter.
Als u een aanwijzer doorgeeft, kopieert u gewoon het adres.
Het is dus nog belangrijker met
pointers als argumenten die gestructureerd zijn omdat structuren groot kunnen zijn.
Zoveel gegevensrepresentaties gebruiken structuren, die verwijzingen naar andere
structuren bevatten.
Je zult dit veel zien in al
je c-programmastructuren die pointers zijn en om de redenen die we noemden.
Het feit dat je ze kunt doorgeven als parameters op oudere versies om
te zien en het is ook efficiënter omdat we
alles doen door waarde die het kopiëren veel efficiënter
is om een adres te kopiëren dan
het kopiëren van alle elementen van deze grote structuur.
Dus het verklaren van een structuur als een aanwijzer vrij eenvoudig.
Wanneer u een variabele definieert als een aanwijzer die moet worden aangeslagen, gebruikt u dat sterretje
gewoon achter het type gegevens.
En we zeiden dat structuren echt een nieuw type zijn.
In dit geval onze altijd belangrijke datumstructuur.
We zeggen gewoon struct date en gebruiken dan de asterisk date pointer,
en je zult dat waarschijnlijk willen initialiseren naar null.
Want onthoud, als je zegt struct date pointer date struct date
date pointer, dat geen geheugen toewijst voor, het creëert
geheugen om de werkelijke aanwijzer op te slaan.
Het creëert geen geheugen voor de gegevens erin.
Je zou dus
ofwel aan dit datumpunt of het adres van een andere structuurdatum kunnen
toewijzen of je zou er ergens anders een geheugen voor kunnen
toewijzen of je zou het ook op
die manier met wat gegevens kunnen initialiseren.
Dus de variabele datumaanwijzer kan net als andere aanwijzers worden toegewezen, u kunt
deze instellen om naar de datum van vandaag te wijzen
met de toewijzingsverklaring, dus als we al een declaratie van de datum van vandaag hadden.
We zouden gewoon de ampersand gebruiken om het adres ervan te krijgen.
Dus we creëren een normale datumstructuur en het is de datum van vandaag.
Dus dat zou een geheugen creëren voor de drie elementen.
En dan maken we onze aanwijzer en we wijzen het gewoon
het adres van de andere datum toe.
Vrij eenvoudig. We hebben dat gedaan met reguliere datatypes,
het is niet anders als je het met structuren doet.
U kunt dan indirect toegang krijgen tot alle leden van de gegevensstructuur waarnaar wordt verwezen door de datumaanwijzer.
Dus we zouden zoiets moeten doen.
Als u toegang wilt krijgen tot
het element van de dagaanwijzerstructuur, moet u het eerst de-refereren.
En dus zou het waarschijnlijk handig zijn om het tussen haakjes te zetten, dus het is heel eenvoudig.
Je moet de verwijzing naar de datumaanwijzer de-referentie om de waarde te
krijgen van waar de datum van vandaag
naar verwijst, de waarde van het adres van de datum van
vandaag waarnaar het verwijst om bepaalde waarden in te stellen.
Dus je zou het de-refereren en
dan zou de puntdag gelijk zijn aan 21 en dat zou 21 toewijzen
aan je dagaanwijzer.
Het bovenstaande zegt alleen maar waar de datum van vandaag ook naar verwijst,
we willen toegang tot die waarde en de dag instellen op 21.
In dit geval zijn de haakjes vereist omdat de
punt een hogere prioriteit heeft dan de asterisk.
Als je de haakjes daar niet hebt geplaatst, wordt het verknoeid omdat het eerst de punt zou proberen
te maken voordat het de aanwijzer naar de aanwijzer kreeg, om hem naar
de gegevens te wijzen.
Dus het zou in wezen proberen toegang te krijgen tot gegevens met een null-aanwijzer.
En dus door de-referentie krijgt u de waarde.
Als we nu structs a pointers gebruiken.
Als we de waarde van maanden willen testen die zijn opgeslagen in de datumstructuur waarnaar wordt verwezen door de datumaanwijzer,
zouden we zoiets als dit kunnen doen.
We de-referentie de aanwijzer, tussen haakjes geplaatst, dus het heeft voorrang op de punt en dan
zeggen we punt maand is gelijk aan 12.
Het is een volkomen geldige syntaxis.
Maar het is een beetje omslachtig.
Dus c heeft zijn eigen syntaxis, dus je hoeft niet alles te
de-refereren en het tussen haakjes te plaatsen voor structuren.
Als u toegang wilt hebben tot waar de structuur naar verwijst, hoeft u
deze niet op deze manier te de-refereren.
Er is een speciale operator in c voor structuren van aanwijzers, en het
is het streepje groter dan.
Het is een streepje gevolgd door het groter dan-teken.
En hierdoor hoeft u de aanwijzer niet te de-refereren.
Dus in plaats van ster x tussen haakjes en dan punt y
te doen, kun je gewoon x-streepje groter dan y zeggen.
Omdat x een aanwijzer is, hoef je er niet naar te verwijzen en je wilt
toegang tot het element binnen die structuur, waar je ook naar verwijst.
Je zult deze syntaxis dus overal tegenkomen. Je zult de
haakjes en de d-referentie niet zien. Het is volkomen geldig, maar u typt meer tekens in.
Het is veel efficiënter om gewoon x-streepje groter dan y te zeggen.
Dus de vorige if-instructie hierboven in plaats van de verwijzing tussen haakjes te verwijderen, hoeft u alleen maar
te zeggen als het streepje van de datumaanwijzer groter is dan de maand.
En het is enigszins intuïtief, omdat het streepje groter dan zegt dat het naar iets wijst.
En dus datumstreepje groter dan maand.
En dus is de datumaanwijzer een aanwijzer en daarom gebruik je het streepje groter dan.
Als dat een geneste structuur was, zou u
het streepje groter maken dan de structuur en dan zou u daarna een
punt moeten plaatsen om toegang te krijgen tot de elementen van de geneste structuur.
Maar omdat de dagaanwijzer een aanwijzer is, moet u het streepje gelijk aan of het
streepje groter dan gebruiken.
Dus hier is een voorbeeld, we maken onze structdatum,
we hebben drie elementen, dan maken we onze onze pointer-datumaanwijzer en we maken vandaag
gewoon een gewone variabele. We wijzen aan onze aanwijzer
het adres van vandaag toe en om vervolgens de feitelijke elementen van
de struct toe te wijzen, gebruiken we dat streepje groter dan en dan kunnen we het afdrukken.
Dus laten we dit in codeblokken bekijken om te zien hoe dit werkt.
Dus ik ga dit voorbeeld hier plaatsen.
En wanneer u structuren definieert, definieert u
ze meestal buiten een functie, omdat u ze dan in elke functie kunt gebruiken.
Het is een soort van globaal. Maar onthoud dat
wanneer u de structuur definieert, u eigenlijk geen geheugen creëert.
U maakt dus nog steeds de variabelen als lokale variabelen of pointers, maar
de eigenlijke definitie ligt buiten de functie.
Dus als u het wilt gebruiken, kunt u het in elke functie gebruiken.
Dus hier bovenaan hebben we een nieuwe structuur gemaakt van het type datum of
naam tot nu toe en het bevat drie gehele getallen, we eindigen het met een puntkomma.
We maken dan een paar variabelen in de main.
Een die vandaag gewoon een normale variabele structdatum is en
dan een die een aanwijzer is. We weten dat het een aanwijzer is omdat er een asterisk voor staat.
We weten dat een aanwijzer wanneer u een aanwijzer maakt, alleen geheugen toewijst om dat adres
op te slaan voor die waarde van die aanwijzer.
Dus we zouden er een adres aan moeten toewijzen, wat we vandaag doen met
ampersand, want dat is eigenlijk een geheugenrapport maken.
Dus nu gaat de datumaanwijzer verwijzen naar wat vandaag
is met het adres van vandaag.
We kunnen er dan gegevens aan toewijzen door dit streepje groter te gebruiken dan
erg handig en gewoon gegevens toewijzen zoals iedereen, gebruik gewoon de toewijzingsoperator.
En als we het dan afdrukken, zult
u merken dat we het niet hoeven te de-refereren om het af te drukken.
Om het
uit te printen, kunnen we gewoon de gegevenstypen voor de formaatspecificaties hier zeggen procent
hoger procent d hetzelfde voor gehele getallen en dan gebruiken we gewoon
dash grader omdat dat eigenlijk het de-referentie onthoudt.
Nu zouden we dit kunnen veranderen en dit zou geldig zijn.
We moeten tussen haakjes zetten en dan moeten we de puntmaand zeggen.
Hoe dan ook is prima, maar wen aan het dashboard dan groter omdat het een betere syntaxis is.
En als we dit nu bouwen,
zul je zien dat het de waarden van de datumaanwijzers
afdrukt en ze zijn allemaal ingesteld op 9 25 en 2015.
Er staat dus dat de datum van vandaag 9 25 15 is. Het was opgemaakt om op die manier af te drukken.
Vrij rechttoe rechtaan dingen.
Onthoud dat streepje groter dan, dat is een
nieuwe syntaxis voor verwijzingen naar structs.
Maar al het andere hier is gewoon normaal.
We weten dat pointers winkeladressen moeten hebben, dus we weten dat
we ofwel dynamisch geheugen moeten toewijzen of dat we er een bestaande structuur aan moeten toewijzen.
Laten we teruggaan en meer praten over structs en pointers.
Laten we het nu hebben over structuren die pointers bevatten.
We weten hoe we een aanwijzer voor een structuur moeten maken.
We zouden geheugen voor die aanwijzer kunnen toewijzen als we geen
bestaand adres van een bestaande aanwijzer willen toewijzen.
Maar je kunt ook elementen in een structuur
hebben die zelf een aanwijzer zijn. Een pointer kan dus ook een lid van een structuur zijn.
We hoeven die tekenreeks niet te gebruiken.
Dus we zouden struct kunnen
zeggen, we zouden het in pointers kunnen noemen en dan zouden we hier in dit voorbeeld twee integers
kunnen gebruiken, twee integer pointers p1 en p2, een perfect geldige syntax om dat te doen.
Dus een structuur die pointers wordt genoemd, is gedefinieerd om twee integer-pointers te bevatten.
De eerste heet p1 en de tweede heet p2.
U kunt een variabele van het type struct in pointers definiëren, net
als normal, struct, int pointers, pointers.
De variabele pointers kunnen nu net als andere structs worden gebruikt.
Pointers is geen pointer.
Het zijn int-pointers. Het bevat twee elementen binnen de
geslagen die wijzers zijn, maar wijzers zelf is geen echte wijzer.
Let daar dus op. Het is een structuurvariabele die twee pointers als leden
heeft, dat is anders.
Dus als we toegang willen hebben tot de elementen
binnen de pointers-variabele die zich in pointers bevindt,
gebruiken we het streepje niet groter dan omdat pointers geen pointer is, het is een struct.
We zouden de punt gebruiken om
toegang te krijgen tot p1 en toegang te krijgen tot p2.
Dus in dit voorbeeld creëren we onze structuur,
we creëren een variabele. Het is geen aanwijzer die aanwijzers wordt genoemd.
En dan creëren we twee gehele getallen,
i1 gelijk aan 100 en i2 die niet is geïnitialiseerd.
Nu zijn p1 en p2 pointers.
Ze moeten dus geldige geheugenadressen bevatten waaraan de adressen
zijn toegewezen.
En dat is wat in i1 en i2 doet.
Wanneer u de integer-variabelen declareert, wordt geheugen toegewezen voor die gehele getallen.
En dus door het adres i1 en i2 toe te wijzen aan p1 en p2, is dat prima, want
voor i1 en i2 is geheugen toegewezen omdat het gehele getallen zijn.
Als de integer-pointers nu geen integer-pointers waren, maar karakter-pointers, dan zou
je dynamisch geheugen moeten toewijzen.
Dus nu gebruiken we alleen gehele getallen, dus kennen we de adressen van de twee gehele getallen toe aan p1 en p2.
We kunnen nu steraanwijzers zeggen. p2 is gelijk aan 97,
min 97.
Waarom moeten we het daar
de-refereren omdat pointers. p2 is waar we naar verwijzen.
Wijzers. pt p2 is een aanwijzer.
We hebben geen toegang tot een element van een structuur.
We laten alle verwijzingen achterwege. p2.
En we gaan dat de waarde toekennen van datgene waar dat naar wijst, naar min 97.
Dus merk het verschil daar.
We maken geen structuuraanwijzer.
We maken een gewone variabele aanwijzer, maar deze
bevat twee elementen die aanwijzers zijn.
Dus als we die twee elementen binnen de structuur willen toewijzen, moeten we ze
de-referentie verwijderen met behulp van de indirecte-operator, en dat is
wat we daar doen.
En dan in onze twee gedrukte verklaringen.
Nogmaals, we willen de waarden afdrukken van waar p1 naar
verwijst, dus we de-refereren hetzelfde
met p2 en dan willen
we ook opnieuw de waarden afdrukken waarnaar pointers verwijst.
Dus in die eerste zeggen we dat i1
gelijk is aan procent I komma's. p1 is gelijk aan
procent I.
Dus de eerste tussen de dubbele aanhalingstekens is gewoon de eigenlijke
tekst aan het uitprinten, het de-refereert niets nadat de komma is waar we de de-referentie doen.
We drukken eerst i1 af, wat 100 is en vervolgens printen
we de wijzers p1 uit, wat 100 zou zijn.
I2 wordt eigenlijk negatief 97
nadat we het aan p2 hebben toegewezen.
Dus hoe zit het met tekenarrays of tekenaanwijzers. In de vorige lezing hebben we
het gehad over hoe je een tekenreeks kunt maken als een
element in een aanwijzer. Maar hoe zit het met
karakteraanwijzers, moeten we
zoiets doen als eerste en laatste
karakterarrays hebben of moeten we gewoon iets doen als eerste
en laatste met karakteraanwijzers als elementen. Wat is de betere optie.
Nou, we zullen zien. Het is echt weer een notatie, maar er zijn voordelen aan het gebruik van de wijzers.
Dus als we verwijzingen naar personages binnen onze elementen maken, is
het meestal een beetje beter.
Maar je moet begrijpen wat hier aan de hand is wanneer
je array element char array als een element of een aanwijzer als een element maakt,
beide zijn geldig. Maar er is een groot verschil.
Dus als we struct namen veep
of vp zeggen en we zeggen Talia en Summers en dan
zeggen we struct pointer naam. Dus onthoud dat structnamen de tekenarrays bevatten.
Struct pointer namen bevat de pointers.
En we initialiseren hier de wijzers die gelijk zijn aan Brad en Fallingjaw.
En dan printen we ze uit. We gaan het eerste element
uitprinten, dat is een karakter a en vp en
dan het eerste element van treas, dat een verwijzing is naar eerst.
Dus de structuur noemt variabele veep.
Wat hier gebeurt, is dat de strings in de structuur worden opgeslagen.
De structuur heeft in totaal 40 bytes toegewezen om de twee namen te
bevatten, het zijn karakterarrays.
Dat is wat er gebeurt als we karakterarrays binnen een aanwijzer maken.
We wijzen 40 bytes toe voor die twee
namen, 20 en 20.
Voor de aanwijzer namen variabele treas, of we nu twee aanwijzers eerst en als laatste
hebben, dit zijn strings die worden opgeslagen waar de compiler stringconstanten opslaat.
De structuur bevat de twee adressen
omdat het wijzers zijn. Pointers bevatten, wat, waarden die adressen zijn.
Dus het enige wat het gaat doen is twee wijzers binnen die structuur toewijzen.
Dat is 16 bytes voor de meeste systemen, pointers meestal 8 bytes of 4 bytes.
De struct p-naamstructuur wijst geen ruimte toe om de tekenreeksen op te slaan,
omdat het alleen ruimte toewijst aan de aanwijzers zelf.
Pointers hebben waarden die adressen zijn.
Het adres waarnaar het verwijst, daar is geen geheugen voor toegewezen.
Dus wanneer u die twee wijzers maakt, is er geen geheugen toegewezen voor die twee wijzers.
Het wijst geen ruimte toe.
Het kan dus alleen worden gebruikt met strings waaraan elders ruimte is toegewezen.
Wanneer je pointers in een structuur hebt, moet je
malloc of calloc gebruiken.
Anders kunnen ze overal worden opgeslagen waar tekenreeksconstanten worden opgeslagen.
En dat is het grote verschil. Dus de aanwijzers en p-naamstructuur moeten
alleen worden gebruikt om strings te beheren die elders in het programma zijn gemaakt en toegewezen.
U wilt daar geen
gegevens aan toewijzen, tenzij u deze dynamisch hebt toegewezen of die
ergens anders is toegewezen, misschien
door een bestaande structuur of zoiets. Maar meestal zul je die aanwijzingen willen malloceren.
Nogmaals, heel anders.
U wijst 40 bytes toe aan deze twee tekenreeksen in de naamstruct.
Voor de p name struct heb je twee pointers.
Daar is geen geheugen voor toegewezen wanneer u een variabele van dat type maakt.
Het creëert gewoon geheugen voor de twee karakteraanwijzers, die elk acht bytes zijn.
Om daadwerkelijk geheugen toe te wijzen voor datgene waarnaar de eerste en de laatste verwijzen, moet je een malloc doen.
Dus een geval waarin het zinvol is om een aanwijzer en een structuur te
gebruiken om strings
te verwerken, is als je dat geheugen dynamisch toewijst.
Dat is meestal wanneer u
het gebruikt, omdat andere toegestane gegevenstypen automatisch het geheugen voor u zullen toewijzen.
U wilt dus een aanwijzer gebruiken om het adres op te slaan.
Dit heeft het voordeel dat je malloc kunt vragen om precies de hoeveelheid ruimte toe te wijzen
die nodig is voor een string. We hebben het gehad over de voordelen van dynamische geheugentoewijzing.
Als je dingen statisch maakt tijdens het compileren, maak je
alleen een specifiek aantal bytes aan.
Wat gebeurt er als je meer bytes nodig hebt, je bent genaaid, je programma gaat niet werken.
Je moet teruggaan en opnieuw compileren. Met dynamisch toegewezen strings kun
je aanpassen, je kunt net zoveel geheugen creëren als je nodig hebt, wat
het veel efficiënter maakt in het programma.
Dus je gaat malloc gebruiken op alle pointers die in een struct zijn gemaakt.
Dus in dit geval heb je een struct genaamd name count.
Je hebt twee aanwijzers, tekenaanwijzers fname en achternaam.
En dan heb je een int, letters.
De twee strings hier binnen zijn niet opgeslagen in de structuur.
We creëren alleen geheugen voor de pointers, die adressen bevatten.
We willen geheugen creëren voor fname en lname voor waar de aanwijzers naar verwijzen.
Dus we willen dat opslaan in een chunk die wordt beheerd door dynamische geheugenlocatie, die malloc gebruikt.
Het adres van de twee strings is wat is opgeslagen, niet waarnaar ze verwijzen.
Dus adressen zijn waar string-afhandelingsfuncties meestal mee werken, wat goed is en
daarom wil je daar pointers gebruiken, want dan hoef je
dat niet te doen, dan kun je ze gewoon een stuk eenvoudiger doorgeven.
Dus hier is een voorbeeld. We hebben een functie genaamd info ophalen.
Er is een wijzer voor nodig.
En we kunnen die wijzer heel gemakkelijk doorgeven.
Nu gaan we ook een andere maken
of voor onze pointer-array waaraan we
worden doorgegeven, we gaan er geheugen
voor toewijzen.
Dus je zult zien dat we een teken maken met de naam temp
en dan slaan we wat gegevens op in die temp.
We vragen de gebruiker om iets te halen. We zijn niet bekend met de sgets, maar het is hetzelfde als de wordt opgeslagen scanf een beetje.
Vervolgens wijzen we geheugen toe voor fname in die aanwijzer en dat doen we net zoals
we geheugen toewijzen aan elk teken. We noemen malloc, we
geven het aantal bytes door.
In dit geval is de str-lengte van 10 plus 1 voor de nulterminator.
En bedenk dan dat malloc een lege ster wordt, dus werpen we hem naar een karakterster.
Maar dit is hier cruciaal. Deze malloc-aanroep is nodig voor alle structuren die pointers bevatten.
Nu hebben we deze aanwijzer doorgegeven en aan de aanwijzer is nooit een
geheugen toegewezen.
Dus we wijzen hier geheugen toe. We kunnen dan heel gemakkelijk onze kopie maken.
We kunnen temp kopiëren naar fname van onze structuur pst die als
parameter is doorgegeven.
En dan kunnen we ze hun achternaam laten invoeren, we kunnen meer geheugen voor
de achternaam malloceren en dan opslaan in de achternaam struct-variabele.
Dit is wat je moet doen als je verwijzingen hebt naar
personages in je structuren, je moet de malloc doen.
Want nogmaals, die wijzers slaan alleen het adres op.
Ze wijzen genoeg geheugen toe om een adres op te slaan, niet
genoeg geheugen om een string op te slaan.
Dus waar dat adres ook naar verwijst, je moet daarvoor geheugen toewijzen en je doet
het net als normaal met de malloc,
het enige verschil is dat je hier het streepje groter dan teken gebruikt
om toegang te krijgen tot het eigenlijke element binnen die struct, wat een is karakteraanwijzer, zodat
u deze eraan kunt toewijzen en dat doet de de-referentie.
Dus je zult met dit spul willen spelen. Dit is heel
gebruikelijk voor karakteraanwijzers in structs.
We hebben een uitdaging waarbij je dit moet doen. Maar speel wat met deze code,
ga binnen codeblokken, begin met het toewijzen van geheugen voor strings
of tekenaanwijzers in structs en kijk hoe je dan
str copy kunt gebruiken om daar daadwerkelijk gegevens in te plaatsen, maar je
moet eerst het geheugen toewijzen voordat je toewijst .
Als je constanten gebruikt zoals in het vorige voorbeeld, wie weet dan waar dat geheugen is toegewezen.
Dus nogmaals, veel belangrijke concepten die in deze lezing worden gepresenteerd.
Dit idee van een structuur die een aanwijzer is in
deze nieuwe syntaxis
waar je het streepje dan groter kunt gebruiken dan in tegenstelling tot
het gebruik van de indirecte-operator, erg leuk.
En dan daadwerkelijk elementen als aanwijzers hebben en hoe
je geheugen moet toewijzen voor tekenaanwijzers. Dank u.