[Powered by Google Translate] [Sectie 4 - Meer Comfortabele] [Rob Bowden - Harvard University] [Dit is CS50. - CS50.TV] We hebben een quiz morgen, voor het geval jullie dat niet wist. Het is eigenlijk op alles wat je zou kunnen hebben gezien in de klas of had moeten zien in de klas. Dat geldt ook voor pointers, ook al zijn ze een zeer recente topic. U dient minstens begrijpen hoge hen. Alles wat was dan verdwenen in de klas moet je begrijpen voor de quiz. Dus als je vragen hebt over hen, dan kunt u nu vragen ze. Maar dit gaat om een ​​zeer student-geleide sessie zijn waar jullie vragen stellen, dus hopelijk mensen hebben vragen. Heeft iemand nog vragen? Ja. >> [Student] Kun je over pointers weer? Ik ga over pointers. Al uw variabelen behoeven te wonen in het geheugen, maar meestal je geen zorgen over te maken en je gewoon zeggen x + 2 en y + 3 en de compiler zal erachter te komen waar de dingen wonen voor u. Zodra je te maken hebt met pointers, nu ben je expliciet het gebruik van deze geheugenadressen. Dus een variabele alleen maar leven op een adres op een bepaald moment. Willen we een pointer te verklaren, is wat het type gaat zien? Ik wil een pointer p verklaren. Hoe ziet het type eruit? [Student] int * p. >> Ja. Dus int * p. En hoe maak ik het wijzen op x? >> [Student] Ampersand. [Bowden] Dus ampersand wordt letterlijk genoemd adres van de marktdeelnemer. Dus als ik zeg & x het wordt steeds het geheugen adres van de variabele x. Dus nu heb ik de aanwijzer p, en overal in mijn code die ik kan gebruiken * p of ik zou kunnen gebruiken x en het zal precies hetzelfde zijn. (* P). Wat is dit nou? Wat betekent die ster bedoel je? [Student] Het betekent een waarde op dat moment. >> Ja. Dus als we kijken naar het, kan het zeer nuttig zijn te trekken uit de schema's waar dit is een klein doosje van het geheugen voor x, wat gebeurt er met de waarde 4, dan hebben we een klein doosje van geheugen voor p, en dus p wijst naar x, dus we trekken een pijl van p naar x. Dus als we zeggen * p we zeggen naar het vak dat is p. Star is volg de pijl en dan doen wat je wilt met die doos daar. Dus ik kan zeggen * p = 7 en dat gaat naar het vak dat is x en verandering die tot en met 7. Of ik zou kunnen zeggen int z = * p * 2, dat is verwarrend, want het is ster, ster. Het is een ster p dereferentie, wordt de andere ster vermenigvuldigen met 2. Merk op dat ik zou kunnen hebben net zo goed vervangen de * p met x. U kunt ze gebruiken op dezelfde manier. En dan later op Ik kan p wijzen op een compleet nieuw ding. Ik kan alleen maar zeggen p = &z; Dus nu p niet meer verwijst naar x, het wijst op z. En elke keer dat ik doe * p het is hetzelfde als het doen van z. Dus het nuttig ding over dit is als we eenmaal beginnen met het krijgen in functies. Het is een beetje nutteloos om een ​​pointer te verklaren dat wijst op iets en dan ben je gewoon dereferentie het als je zou kunnen hebben gemaakt van de oorspronkelijke variabele te beginnen. Maar als je in functies - dus laten we zeggen dat we een functie, int foo, dat duurt een pointer en net doet * p = 6; Zoals we eerder zagen met swap, kunt u niet doen van een effectieve swap en een aparte functie door gewoon het passeren van gehele getallen omdat alles in C wordt altijd doorgeven als waarde. Zelfs als je pointers passeren je doorgeven als waarde. Het is gewoon zo gebeurt het dat deze waarden zijn geheugenadressen. Dus als ik zeg foo (p), ik ben het passeren van de aanwijzer in de functie foo en dan foo doet * p = 6; Zo binnen van deze functie * p nog gelijk aan x, maar ik kan geen gebruik maken van x binnenkant van die functie omdat het niet scoped binnen die functie. Dus * p = 6 is de enige manier waarop ik kan een lokale variabele van een andere functie te openen. Of, nou ja, pointers zijn de enige manier waarop ik kan een lokale variabele van een andere functie te openen. [Student] Laten we zeggen dat je wilde een pointer terug te keren. Hoe precies doe je dat? [Bowden] Terug een pointer als in iets als int y = 3; return & y? >> [Student] Ja. [Bowden] Oke. Je moet nooit doen. Dit is slecht. Ik denk dat ik zag in deze slides u begon het zien van dit hele schema van het geheugen waar hier heb je het geheugen adres 0 en hier beneden heb je het geheugen adres 4 optredens of 2 om de 32. Dus dan heb je een aantal dingen en wat spullen en dan heb je je stack en je hebt je hoop, dat je gewoon begonnen met het leren over, opgroeien. [Student] Is niet de hoop boven de stapel? Ja. De hoop is op de top, is het niet? >> [Student] Nou, hij zet 0 op de top. [Student] Oh, hij zet 0 op de top. >> [Student] Oh, oke. Disclaimer: Overal met CS50 je gaat om het te zien op deze manier. >> [Student] Oke. Het is gewoon dat als je eerst zien stapels, zoals wanneer je denkt aan een stapel je denkt van het stapelen van dingen op de top van elkaar. Dus we hebben de neiging om deze flip rond, zodat de stapel groeit op als een stapel normaal zou doen in plaats van de stapel opknoping beneden. >> [Student] Niet hopen technisch te groeien, hoewel? Het hangt af van wat je bedoelt met opgroeien. De stack en heap groeien altijd in tegengestelde richting. Een stapel is altijd groeien op in de zin dat het wordt groot naar hogere geheugenadressen, en de hoop groeit naar beneden in dat het groeit in de richting van lagere geheugenadressen. Dus de top is 0 en de onderste is hoog geheugenadressen. Ze zijn zowel groeiende, alleen in tegengestelde richtingen. [Student] Ik bedoelde dat omdat je zei dat je stack op de bodem omdat het lijkt intuïtief omdat de stack te beginnen bovenaan een hoop, hoop is op de top van zichzelf ook, dus Dat is - >> Ja. U kunt ook denken aan de hoop zo opgroeien en groter, maar de stapel meer. Dus de stapel is degene die we soort van willen laten zien opgroeien. Maar overal waar je kijkt op een andere manier gaat adres 0 bovenaan verschijnen en de hoogste geheugenadres op de bodem, dus dit is uw gebruikelijke uitzicht op het geheugen. Heeft u een vraag? [Student] Kun je ons meer vertellen over de hoop? Ja. Ik zal dat in een seconde. Ten eerste, terug te gaan naar waarom terugkerende & y is een slechte zaak, op de stapel heb je een heleboel stack frames waarin alle functies weer te geven die zijn genoemd. Dus negeren vorige dingen, is de bovenkant van je stack altijd naar de hoofdfunctie worden want dat is de eerste functie dat wordt gebeld. En dan, als u een andere functie aan te roepen, wordt de stapel gaat naar beneden groeien. Dus als ik een bepaalde functie, foo, bellen en krijgt het zijn eigen stack frame, gevraagd kan een functie, een bar, het krijgt zijn eigen stack frame. En de bar zou kunnen zijn recursieve en het zou noemen zichzelf, en zo dat tweede gesprek bar gaat zijn eigen stack frame te krijgen. En zo wat er in deze stack frames zijn alle van de lokale variabelen en alle functies argumenten - Elke dingen die lokaal binnen het bereik van deze functie te gaan in deze stack frames. Dus dat betekent dat toen ik zei iets als bar is een functie, Ik ga gewoon naar een integer dan te verklaren en een pointer terug te keren naar die integer. Dus waar komt y wonen? [Student] y woont in bar. >> [Bowden] Ja. Ergens in een klein plein van het geheugen is een Littler plein dat y in zich heeft. Als ik terugkom & y, ben ik terug een pointer naar dit kleine blok van het geheugen. Maar toen een functie terugkeert, wordt de stack frame popped uit de stapel. En dat is waarom het heet stack. Het is net als de stapel datastructuur, als je weet wat dat is. Of zelfs als een stapel trays is altijd het voorbeeld, belangrijkste zal gaan op de bodem, dan is de eerste functie die u belt zal gaan op de top van dat, en je kunt niet terug naar de belangrijkste totdat u terug bent van alle functies die zijn genoemd die zijn geplaatst bovenop. [Student] Dus als je deed de terugkeer van de & y, die waarde is onderhevig aan wijzigingen zonder voorafgaande kennisgeving. Ja, het is - >> [student] Het kan worden overschreven. >> Ja. Het is volledig - Als u probeert en - Dit zou ook een int * bar omdat het terugsturen van een pointer, zodat de return type is int *. Als u probeert om de return waarde van deze functie te gebruiken, het is onbepaald gedrag want dat pointer wijst op slecht geheugen. >> [Student] Oke. Dus wat als, bijvoorbeeld, u verklaarde int * y = malloc (sizeof (int))? Dat is beter. Ja. [Student] We hadden het over hoe als we dingen sleep om onze prullenbak ze zijn niet echt gewist, we verliezen hun pointers. Dus in dit geval weten we eigenlijk wissen van de waarde of is het er nog steeds in het geheugen? Voor het grootste deel, het gaat om nog steeds zijn. Maar laten we zeggen dat we toevallig een andere functie, baz bellen. Baz gaat zijn eigen stack frame te krijgen hier. Het zal worden overschreven alle van dit spul, en dan als je later nog eens proberen en gebruik de pointer die je hebt voor, het is niet van plan om dezelfde waarde te zijn. Het zal net zijn veranderd omdat je de naam van de functie baz. [Student] Maar hadden we niet, zouden we nog steeds 3? [Bowden] Naar alle waarschijnlijkheid, zou je. Maar je kunt niet op vertrouwen. C zegt gewoon onbepaald gedrag. [Student] Oh, het doet. Oke. Dus als je wilt een pointer terug te keren, dit is waar malloc komt in gebruik. Ik ben eigenlijk schrijf gewoon terug malloc (3 * sizeof (int)). We gaan dan malloc meer in een tweede, maar het idee van malloc is al uw lokale variabelen altijd op de stapel. Alles wat is malloced gaat op de heap, en het zal voor eeuwig en altijd op de heap totdat u expliciet bevrijden. Dus dit betekent dat wanneer je malloc iets, het gaat om te overleven na de functie terugkeert. [Student] Zal het overleven nadat het programma stopt? >> Nee. Oke, dus het gaat om daar te zijn totdat het programma is helemaal klaar draait. >> Ja. We kunnen gaan over de details van wat er gebeurt wanneer het programma stopt. Mogelijk moet u me eraan te herinneren, maar dat is een apart ding helemaal. [Student] Dus malloc creëert een pointer? >> Ja. Malloc - >> [student] Ik denk dat malloc wijst een blok van het geheugen dat een pointer kan gebruiken. [Bowden] Ik wil dat schema weer. >> [Student] Dus deze functie werkt, hoewel? [Student] Ja, malloc wijst een blok van het geheugen die u kunt gebruiken, en dan geeft het adres van het eerste blok van dat geheugen. [Bowden] Ja. Dus als je malloc, je grijpen sommige blok van het geheugen dat is op dit moment in de heap. Als de hoop te klein is, dan is de hoop is gewoon om te groeien, en het groeit in deze richting. Dus laten we zeggen dat de hoop is te klein. Dan is het op het punt om een ​​beetje te groeien en een pointer terug te keren naar dit blok dat net groeide. Als je gratis spullen, je bent meer ruimte in de hoop het maken, dus dan een later bellen om malloc kunt hergebruiken dat het geheugen die u eerder had bevrijd. Het belangrijkste ding over malloc en free is dat het geeft je volledige controle gedurende de levensduur van deze geheugenblokken. Globale variabelen zijn altijd levend. Lokale variabelen zijn leven binnen hun bereik. Zodra je voorbij een accolade, de lokale variabelen zijn dood. Malloced geheugen leeft wanneer je wilt om te leven en dan wordt losgelaten wanneer u hem dat vrij te geven. Dat zijn eigenlijk de enige 3 soorten geheugen, echt waar. Er is automatische geheugenbeheer, dat is de stapel. Dingen gebeuren automatisch voor u. Wanneer u int x zeggen, is het geheugen toegewezen voor int x. Als x buiten het bereik valt, wordt het geheugen teruggewonnen voor x. Dan is er dynamisch geheugenbeheer, dat is wat malloc is, dat is wanneer je de controle hebt. Je dynamisch beslissen wanneer het geheugen wel en niet moet worden toegewezen. En dan is er statische is, dat betekent gewoon dat het voor altijd leeft, dat is wat globale variabelen zijn. Ze zijn gewoon altijd in het geheugen. Vragen? [Student] Kan je een blok te definiëren alleen door het gebruik van accolades maar zonder te beschikken over een if-statement of een while-opdracht of iets dergelijks? U kunt een blok als in een functie, maar dat heeft accolades ook. [Student] Dus je kunt niet alleen maar als een willekeurige paar accolades in je code dat de lokale variabelen? >> Ja, dat kan. Binnenkant van int bar konden we hebben {int y = 3;}. Dat zou hier zijn. Maar dat bepaalt volledig de omvang van int y. Na die tweede accolade, kan y niet meer gebruikt worden. Je hebt bijna nooit doen, dat wel. Om terug te komen wat er gebeurt als een programma eindigt, er is een beetje een misvatting / halve leugen dat we geven om gewoon dingen makkelijker te maken. Wij zeggen jullie dat als je geheugen toewijzen je bent toewijzing van een aantal portie RAM geheugen voor die variabele. Maar je bent niet echt aan te raken RAM ooit in uw programma's. Als je er van vindt, hoe ik trok - En eigenlijk, als je door in GDB zie je hetzelfde. Ongeacht hoe vaak u met uw programma of welk programma je draait, de stapel zal altijd beginnen - je bent altijd gaat om variabelen rond adres oxbffff iets te zien. Het is meestal ergens in die regio. Maar hoe kan 2 programma's mogelijk voor verwijzingen naar hetzelfde geheugen? [Student] Er is een aantal willekeurige aanduiding van waar oxbfff hoort te zijn op het RAM-geheugen die daadwerkelijk kan worden in verschillende plaatsen afhankelijk van wanneer de functie is aangeroepen. Ja. De term is virtueel geheugen. Het idee is dat elke proces, ieder programma dat wordt uitgevoerd op de computer heeft zijn eigen - laten we aannemen dat 32 bits - volledig onafhankelijk adresruimte. Dit is de adresruimte. Het heeft zijn eigen volledig onafhankelijk 4 GB te gebruiken. Dus als je 2 programma's tegelijkertijd, dit programma ziet 4 gigabyte aan zichzelf, dit programma ziet 4 gigabyte aan zichzelf, en het is onmogelijk voor dit programma te dereference een pointer en eindigen met het geheugen van dit programma. En wat virtueel geheugen is een afbeelding van een proces adresruimte de werkelijke dingen op RAM. Dus is het aan uw besturingssysteem om te weten dat, hey, wanneer deze kerel referentie aan pointer oxbfff, dat werkelijk betekent dat hij wil byte RAM 1000, terwijl als dit programma referentie aan oxbfff, hij wil echt RAM byte 10000. Ze kunnen willekeurig groot zijn. Dit is zelfs het geval van de dingen in een enkele processen adresruimte. Dus als het ziet alle 4 gigabyte aan zichzelf, maar laten we zeggen - [Student] Heeft elke enkel proces - Laten we zeggen dat u een computer met slechts 4 gigabyte aan RAM-geheugen. Heeft elk proces zien dat de hele 4 gigabytes? >> Ja. Maar de 4 gigabyte ziet is een leugen. Het is gewoon het denkt dat het heeft dit alles het geheugen, omdat het niet weet enig ander proces bestaat. Het zal alleen gebruik maken van zo veel geheugen als het daadwerkelijk nodig heeft. Het besturingssysteem is niet van plan om RAM te geven aan dit proces als het niet gebruik van een geheugen in deze hele regio. Het gaat niet om het geheugen voor die regio. Maar het idee is dat - ik probeer te bedenken - ik kan niet denken van een analogie. Analogieën zijn hard. Een van de problemen van het virtuele geheugen of een van de dingen die het is het oplossen van dat processen moeten volledig bewust van elkaar. En zo kunt u schrijven een programma dat net referentie aan elke pointer, graag gewoon een programma schrijven dat zegt * (ox1234), en dat is dereferentie geheugenadres 1234. Maar het is aan het besturingssysteem om vervolgens vertalen wat 1234 betekent. Dus als 1234 gebeurt er met een geldig geheugenadres zijn voor dit proces, alsof het op de stapel of iets, dan zal dit de terugkeer van de waarde van dat geheugenadres wat het proces weet. Maar als 1234 is geen geldig adres, zoals het gebeurt landen om in een klein stukje van het geheugen hier dat is buiten de stack en buiten de heap en je hebt niet echt gebruikt dat, dan is dat als je dingen als segfaults omdat je het aanraken van het geheugen dat je niet moet aanraken. Dit geldt ook - Een 32-bits systeem, 32-bits betekent dat je 32 bits om een ​​geheugenadres te definiëren. Het is de reden waarom pointers zijn 8 bytes, omdat 32 bits zijn 8 bytes - of 4 bytes. Pointers zijn 4 bytes. Dus als je een pointer als oxbfffff zien, dat wil zeggen - Binnen een bepaald programma kan je gewoon bouwen willekeurige pointer, overal van ox0 tot os 8 f's - ffffffff. [Student] Zei je niet dat ze 4 bytes? >> Ja. [Student] Dan elke byte zal hebben - >> [Bowden] Hexadecimaal. Hexadecimale - 5, 6, 7, 8. Dus pointers je gaat altijd zien in hexadecimaal. Het is gewoon de manier waarop we classificeren pointers. Elke 2 hexadecimale tekens is 1 byte. Dus er komt wel 8 hexadecimale cijfers voor 4 bytes. Dus elke aanwijzer op een 32-bits systeem gaat worden 4 bytes, Dit betekent dat in uw proces kunt u bouwen elke willekeurige 4 bytes en maak een wijzer van te maken, Dit betekent dat voor zover zij bekend is, kan betrekking hebben op een gehele 2 de 32 bytes van het geheugen. Hoewel het niet echt toegang hebben tot dat, zelfs als uw computer enkel 512 megabytes, hij denkt het heeft die veel geheugen. En het besturingssysteem is slim genoeg dat het alleen zal toewijzen wat je eigenlijk nodig hebt. Het is niet alleen te gaan, oh, een nieuw proces: 4 optredens. Ja. >> [Student] Wat betekent de os bedoel je? Waarom schrijf je dat? Het is gewoon het symbool voor hexadecimaal. Als u een nummer beginnen te zien met os, de opeenvolgende dingen zijn hexadecimaal. [Student] Je had uit te leggen over wat er gebeurt wanneer een programma eindigt. >> Ja. Wat gebeurt er wanneer een programma wordt beëindigd, is het besturingssysteem net wist de toewijzingen die het heeft voor deze adressen, en dat is het. Het besturingssysteem kan nu geef dat het geheugen naar een ander programma te gebruiken. [Student] Oke. Dus als je iets toe te wijzen aan de berg of de stapel of globale variabelen of wat dan ook, ze allemaal verdwijnen zodra het programma eindigt omdat het besturingssysteem is nu vrij om dat geheugen te geven aan een ander proces. [Student] Ook al zijn er waarschijnlijk nog waarden geschreven? >> Ja. De waarden zijn waarschijnlijk nog steeds. Het is gewoon dat het gaat om moeilijk te krijgen op hen. Het is veel moeilijker om bij hen dan het is om op een verwijderd bestand omdat het verwijderde bestand soort zit er voor een lange tijd en de harde schijf is een stuk groter. Dus het gaat om de verschillende delen van het geheugen te overschrijven voordat het gebeurt te overschrijven het stuk van het geheugen dat dat bestand gebruikt om te zijn. Maar het hoofdgeheugen, RAM, fietst u door een stuk sneller, dus het zal zeer snel worden overschreven. Vragen over dit of iets anders? [Student] Ik heb vragen over een ander onderwerp. >> Oke. Heeft iemand vragen over dit? Oke. Ander onderwerp. >> [Student] Oke. Ik ging door een aantal van de praktijk testen, en in een van hen had het over de sizeof en de waarde wordt geretourneerd of verschillende variabele types. >> Ja. En het zei dat zowel int en lange zowel terugkeer 4 dus, ze zijn allebei 4 bytes lang. Is er een verschil tussen een int en een lange, of is het hetzelfde? Ja, er is een verschil. De C standaard - Ik ga waarschijnlijk verpesten. De C standaard is net als wat C is, de officiële documentatie van C. Dit is wat het zegt. Dus de C standaard zegt alleen dat een char zal voor eeuwig en altijd 1 byte. Alles daarna - korte altijd precies gedefinieerd als groter dan of gelijk aan een char. Dit kan strikt groter is dan, maar niet positief. Een int net gedefinieerd als groter dan of gelijk aan een korte. En een lange is net gedefinieerd als groter dan of gelijk aan een int. En een lange lange groter is dan of gelijk is aan een lang. Dus het enige wat de C standaard definieert is de relatieve ordening van alles. De werkelijke hoeveelheid geheugen die dingen nemen is over het algemeen tot de uitvoering, maar het is vrij goed gedefinieerd op dit punt. >> [Student] Oke. Dus shorts zijn bijna altijd gaat worden 2 bytes. Ints zijn bijna altijd gaat worden 4 bytes. Lange longs zijn bijna altijd zal zijn 8 bytes. En verlangt, het hangt af van het feit of u een 32-bits of een 64-bit systeem. Zo lang zal overeenkomen met het type systeem. Als u een 32-bits systeem zoals de Appliance, gaat het om 4 bytes. Als u een 64-bits als een hoop van de recente computers, het gaat om 8 bytes. Ints zijn bijna altijd 4 bytes op dit punt. Lange longs zijn bijna altijd 8 bytes. In het verleden ints gebruikt louter 2 bytes. Maar let erop dat dit volledig al deze relaties van groter dan en gelijk aan voldoet. Zolang perfect mag dezelfde grootte als een integer is, en het is ook toegestaan ​​om de dezelfde grootte als een lange lang zijn. En toevallig zijn dat 99,999% van de systemen, zal gelijk aan ofwel een int of een lange lang. Het is maar net 32-bit of 64-bit. >> [Student] Oke. In drijvers, hoe is de decimale punt aangewezen in termen van bits? Zoals als binaire? >> Ja. U hoeft niet om te weten dat voor de CS50. Je hoeft niet eens te weten dat er in 61. Je hoeft niet die echt leren in een cursus. Het is gewoon een voorstelling. Ik vergeet de exacte beetje volkstuinen. Het idee van floating point is dat je een bepaald aantal bits te vertegenwoordigen wijzen - Kortom, alles is in wetenschappelijke notatie. Dus kennen een specifiek aantal bits aan het getal zelf vertegenwoordigen als 1,2345. Ik kan een nummer nooit vertegenwoordigen met meer cijfers dan 5. Dan ook kennen een specifiek aantal bits zodat het de neiging om als je kunt alleen oplopen tot een aantal, zoals dat is de grootste exponent kunt u, en je kunt alleen naar beneden naar een bepaalde exponent, als dat is de kleinste exponent je kunt hebben. Ik herinner me niet de exacte manier bits toegekend aan elk van deze waarden, maar een aantal bits gewijd aan 1,2345, een aantal bits gewijd aan de exponent, en het is alleen mogelijk om vormen een exponent van een bepaalde grootte. [Student] En een dubbele? Is dat als een extra lange float? >> Ja. Het is hetzelfde als een float, behalve nu dat u gebruikt 8 bytes in plaats van 4 bytes. Nu zult u in staat zijn om 9 cijfers of 10 cijfers te gebruiken, en deze kunnen oplopen tot 300 in plaats van 100. >> [Student] Oke. En drijft zijn ook 4 bytes. >> Ja. Nou, nogmaals, het hangt waarschijnlijk overall op algemene uitvoering, maar drijft zijn 4 bytes, tweepersoonskamers zijn 8. Doubles zijn dubbel genoemd omdat ze het dubbele van de grootte van de praalwagens. [Student] Oke. En zijn er verdubbelt dubbel? >> Er zijn niet. Ik denk dat - >> [student] Zoals lang longs? >> Ja. Ik denk het niet. Ja. [Student] Op-test van vorig jaar was er een vraag over de belangrijkste functie dat u een deel van uw programma. Het antwoord was dat het niet hoeft te een deel van uw programma. In welke situatie? Dat is wat ik zag. [Bowden] Het lijkt erop - >> [student] Welke situatie? Heeft u het probleem? >> [Student] Ja, ik kan zeker trek het omhoog. Het hoeft niet zo te zijn, technisch, maar kort gezegd: het gaat worden. [Student] Ik zag er een op een andere jaar. Het was alsof Waar of niet waar: Een geldige - >> Oh, een C-bestand.? . [Student] Elke c bestand moet - [zowel gesproken in een keer - onverstaanbaar] Oke. Dus dat is een aparte. Een. C bestand moet enkel bevatten functies. U kunt een dossier samen in machine code, binaire, wat dan ook, zonder dat het uitvoerbare nog niet. Een geldige uitvoerbare moet een hoofdfunctie. U kunt schrijven 100 functies in 1 bestand, maar geen grote en dan die naar beneden compileren naar binair, dan schrijf je een ander bestand dat alleen de belangrijkste, maar het noemt een aantal van deze functies in deze binair bestand hier. En dus als je de executable maken, dat is wat de linker doet is het een combinatie van deze 2 binaire bestanden in een uitvoerbaar. Dus een. C bestand hoeft niet een hoofdfunctie te hebben. En op grote code bases zie je duizenden. C bestanden en 1 hoofdbestand. Meer vragen? [Student] Er was een andere vraag. Het zei te maken is een compiler. Waar of niet waar? En het antwoord was vals, en ik begreep waarom het is niet zoals Clang. Maar hoe noemen we maken als het niet? Eigenlijk te maken is gewoon - Ik kan precies zien wat het noemt. Maar het loopt gewoon commando's. Te maken. Ik kan trekken deze omhoog. Ja. Oh, ja. Zorg dat doet ook. Dit zegt het doel van de make werktuig is om automatisch te bepalen welke delen van een groot programma opnieuw gecompileerd moeten worden en geeft het commando's om ze opnieuw te compileren. U kunt maken bestanden die zijn absoluut enorm. Maak kijkt naar de tijdstempels van bestanden en, zoals we eerder hebben gezegd, kan je het compileren individuele bestanden naar beneden, en het is niet tot je bij de linker dat ze samengevoegd tot een uitvoerbaar. Dus als je 10 verschillende bestanden en u een wijziging aanbrengt in een van hen, dan wat merk gaat doen is gewoon opnieuw compileren dat 1 bestand en dan samen opnieuw koppelen alles. Maar het is veel dommer dan dat. Het is aan jou om volledig te definiëren dat dat is wat het zou moeten doen. Het heeft standaard de mogelijkheid om deze tijdstempel spul te herkennen, maar je kunt een merk-bestand om iets te doen. U kunt een make file, zodat wanneer u typt maken het net cd's naar een andere map. Ik was gefrustreerd omdat ik overstag alles binnenkant van mijn Appliance en dan ik de PDF van de Mac. Dus ik ga naar Finder en ik kan doen Ga, Verbind met server, en de server ik aansluiten op is mijn Appliance, en dan heb ik open het PDF-bestand dat wordt samengesteld door LaTeX. Maar ik was gefrustreerd omdat elke keer als ik die nodig is om de PDF te vernieuwen, Ik moest het kopiëren naar een specifieke directory dat het zou kunnen openen en het was al vervelend. Dus in plaats daarvan schreef ik een merk-bestand, die u moet definiëren hoe het dingen maakt. Hoe maak je in dit PDF-LaTeX. Net als elke andere merk-bestand - of Ik denk dat je nog niet het merk bestanden gezien, maar we hebben in de Appliance een wereldwijde merk-bestand dat gewoon zegt, als je het compileren van een C-bestand, gebruik Clang. En dus even in mijn make-bestand dat ik zeg ik, Dit bestand dat u gaat te willen compileren met PDF LaTeX. En dus is het PDF-LaTeX dat doet het compileren. Maak niet compileren. Het is gewoon het uitvoeren van deze commando's in de volgorde ik heb opgegeven. Dus het PDF LaTeX wordt uitgevoerd, kopieert deze naar de directory wil ik dat het gekopieerd moet worden, Het cd's naar de directory en doet andere dingen, maar alles wat het doet is te herkennen wanneer een bestand wordt gewijzigd, en als het verandert, dan zal het uitvoeren van de commando dat het zou moeten lopen wanneer het bestand wordt gewijzigd. >> [Student] Oke. Ik weet niet waar het wereldwijde merk bestanden zijn voor mij om het te controleren. Andere vragen? Alles wat uit het verleden quizzen? Elke pointer dingen? Er zijn subtiele dingen met pointers, zoals - Ik ga niet in staat zijn om een ​​quizvraag te vinden op het - maar net als dit soort dingen. Zorg ervoor dat je begrijpt dat als ik zeg int * x * y - Dit is precies niets hier, denk ik. Maar zoals * x * y, dat zijn 2 variabelen die op de stapel. Als ik zeg x = malloc (sizeof (int)), x is nog steeds een variabele op de stack, malloc is wat blok over in de hoop, en we hebben x wijzen op de heap. Dus iets op de stapel wijst op de heap. Wanneer je malloc iets, je onvermijdelijk te slaan binnenkant van een pointer. Zodat pointer op de stapel, de malloced blok op de heap. Veel mensen in de war raken en zeggen: int * x = malloc, x op de heap. Nee, wat x wijst naar is op de heap. x zelf is op de stapel, tenzij om wat voor reden je hebt x een globale variabele, In dat geval toevallig in een ander gebied van het geheugen. Dus het bijhouden, deze doos en pijl diagrammen zijn vrij normaal voor de quiz. Of als het niet op quiz 0, zal het op quiz 1. U moet weten van al deze, de stappen in het opstellen van omdat je moest vragen op die te beantwoorden. Ja. [Student] Kunnen we gaan over die stappen - >> Tuurlijk. Voordat stappen en samenstellen hebben we preprocessing, compileren, monteren, en het koppelen van. Preprocessing. Wat doet dat? Het is de gemakkelijkste stap in het - goed, niet zoals - dat betekent niet dat het moet duidelijk zijn, maar het is de gemakkelijkste stap. Jullie kunnen implementeren jezelf. Ja. [Student] Neem wat je hebt in je ook als deze en het kopieert en dan ook definieert. Het ziet er voor dingen als # include en definiëren #, en het gewoon kopieert en plakt wat die eigenlijk betekenen. Dus als je zegt dat # include cs50.h, wordt de preprocessor kopiëren en plakken cs50.h in die lijn. Als je zegt # define x te zijn 4, de preprocessor gaat door het hele programma en vervangt alle instanties van x met 4. Dus de preprocessor neemt een geldig C-bestand en voert een geldig C-bestand waar de dingen zijn gekopieerd en geplakt. Dus nu compileren. Wat doet dat? [Student] Het gaat van C naar binair. [Bowden] Het doet er helemaal niet naar binair. [Student] Voor machine-code dan? >> Het is niet machine code. [Student] Vergadering? >> Vergadering. Het gaat om Vergadering voordat het gaat helemaal naar C-code, en de meeste talen zoiets doen. Kies een willekeurige high-level taal, en als je gaat om het te compileren, is het waarschijnlijk te compileren in stappen. Eerst gaat Python compileren naar C, dan zal het naar C compileren Vergadering, en dan Vergadering gaat worden vertaald naar binair. Dus samenstellen gaat om het te brengen van C naar Assembly. Het woord samenstellen betekent meestal brengen het van een hoger niveau naar lagere programmeertaal. Dus dit is de enige stap in compilaties waar je begint met een high-level taal en eindigen in een low-level taal, en dat is de reden waarom de stap heet compileren. [Student] Tijdens het opstellen, laten we zeggen dat je hebt gedaan # include cs50.h. Zal de compiler opnieuw compileren van de cs50.h, zoals de functies die daar, en omgezet in Assembly code als goed, of zal het kopiëren en plakken iets dat is al pre-Assembly? cs50.h zal vrij veel nooit in Vergadering. Dingen als functie prototypes en dingen die er zijn voor jou om voorzichtig te zijn. Het garandeert dat de compiler kan dingen te controleren alsof je belfuncties met de juiste return typen en de juiste argumenten en dat soort dingen. Dus cs50.h worden voorbewerkt in het bestand, en dan wanneer het samenstellen van Het is eigenlijk weggegooid nadat het zorgt ervoor dat alles correct wordt genoemd. Maar de functies gedefinieerd in de CS50 bibliotheek, die gescheiden zijn van cs50.h, die zullen niet afzonderlijk worden opgesteld. Dat is eigenlijk zal naar beneden komen in de koppeling stap, dus we zullen krijgen om dat in een seconde. Maar eerst, wat is het monteren? [Student] Vergadering binaire? >> Ja. Montage. We noemen het niet compileren omdat Vergadering is vrij veel een zuivere vertaling van binaire. Er is heel weinig logica in gaan van Vergadering binaire. Het is net als kijken in een tabel, oh, hebben we deze instructie; die overeenkomt met binaire 01110. En dus de bestanden die de montage over het algemeen uitgangen zijn. O bestanden. En. O-bestanden zijn wat we zeiden voor, hoe een bestand hoeft niet een hoofdfunctie hebben. Elk bestand kan worden samengesteld tot een. O-bestand, zolang het is een geldige C-bestand. Het kan bundelen tot. O. Nu, het koppelen is wat eigenlijk een stelletje brengt. O bestanden en brengt ze naar een uitvoerbaar. En dus wat linking doet is kunt u van de CS50 bibliotheek te denken als een. O-bestand. Het is een reeds gecompileerd binair bestand. En dus als het samenstellen van je bestand, uw hello.c, waarin wordt opgeroepen GetString, hello.c wordt samengesteld naar hello.o, hello.o is nu in binaire. Het maakt gebruik van GetString, dus het moet om over te gaan naar cs50.o, en de linker smooshes ze samen en kopieert GetString in dit bestand en komt met een uitvoerbaar dat alle functies die het nodig heeft. Dus cs50.o is niet echt een O-bestand, maar het is dichtbij genoeg dat er geen fundamenteel verschil. Dus koppelen net brengt een aantal bestanden bij elkaar die afzonderlijk alle functies bevatten moet ik gebruiken en creëert het uitvoerbare bestand dat daadwerkelijk wordt uitgevoerd. En dus dat is ook wat we zeiden eerder waar u kunt 1000 hebben. c-bestanden, kunt compileren ze allemaal. o-bestanden, die waarschijnlijk zal een tijdje duren, dan moet je wijzigen 1. c bestand. U hoeft alleen maar dat 1. C-bestand en vervolgens opnieuw koppelt alles hercompileren, verbinden alles weer bij elkaar. [Student] Als we het koppelen we schrijven lcs50? Ja, zo-lcs50. Die vlag signalen naar de linker dat je moet koppelen in die bibliotheek. Vragen? Hebben we gegaan over binaire, andere dan die 5 seconden in de eerste lezing? Ik denk het niet. U moet weten alle grote Os dat we gegaan, en je moet in staat zijn om, als we gaven je een functie, moet je in staat om te zeggen het is groot O ruwweg,. Of nou ja, grote O is ruw. Dus als je ziet geneste for-lussen een lus over hetzelfde aantal dingen, zoals int i, i > [student] n het kwadraat. >> Het de neiging om n kwadraat. Als u triple genest, het de neiging om n blokjes. Dus dat soort dingen moet je in staat om onmiddellijk te wijzen. Je moet insertion sort en bubble sort kennen en soort en al die samen te voegen. Het is makkelijker om te begrijpen waarom zij zijn degenen n vierkant en n log n en dat allemaal want ik denk dat er op een quiz een jaar wanneer we in principe je gaf een implementatie van bubble sort en zei: "Wat is de looptijd van deze functie?" Dus als je het herkent als bubble sort, dan kunt u meteen zeggen n kwadraat. Maar als je gewoon naar kijkt, hoeft u niet eens nodig om het een bubble sort realiseren; kun je gewoon zeggen dat dit dit en dit doen. Dit is n kwadraat. [Student] Zijn er moeilijke voorbeelden die je kan bedenken, als een vergelijkbaar idee van het uitzoeken? Ik denk niet dat we zouden geven u geen moeilijke voorbeelden. De bubble sort ding is ongeveer net zo hard als we zouden gaan, en zelfs dat, zolang je begrijpt dat je itereren over de array voor elk element in de array, wordt die gaat iets dat n kwadraat zijn. Er zijn algemene vragen, zoals hier hebben we - Oh. Alleen de andere dag, Doug beweerde, "Ik heb uitgevonden een algoritme dat een array kunnen sorteren "Van n getallen in O (log n) tijd!" Dus hoe kunnen we weten dat dat onmogelijk is? [Onverstaanbaar student reactie] >> Ja. Op zijn minst, moet u elk element te raken in de array, dus het is onmogelijk om te sorteren een scala aan - Als alles in orde ongesorteerd, dan zul je raken alles in de array, dus het is onmogelijk om het te doen in minder dan O van n. [Student] U heeft ons laten zien dat voorbeeld van de mogelijkheid om het te doen in O n als u veel geheugen. >> Ja. En Dat is - ik vergeet wat Dat is - Is het tellen sorteren? Hmm. Dat een geheel getal sorteeralgoritme. Ik was op zoek naar de speciale naam voor dit dat ik niet kon herinneren van vorige week. Ja. Dit zijn de soorten van soorten die dingen kunnen bereiken in grote O van n. Maar er zijn beperkingen, zoals je kunt alleen gebruik maken van gehele getallen tot een bepaald aantal. Plus als je probeert om iets te that's sorteren - Als uw array is 012, -12, 151, 4 miljoen, dan is dat enkel element gaat volledig ruïneren de hele sorteren. Vragen? [Student] Als je een recursieve functie en het maakt de recursieve oproepen binnen een return-statement, dat is de staart recursieve, en zo zou dat niet meer geheugen gebruiken tijdens runtime of het zou op z'n minst vergelijkbaar geheugen als een iteratief oplossing? [Bowden] Ja. Het zou waarschijnlijk iets trager, maar niet echt. Staart recursieve is vrij goed. Op zoek weer op stapel frames, laten we zeggen dat we de belangrijkste zijn en we hebben int bar (int x) of iets dergelijks. Dit is geen perfect recursieve functie, maar return bar (x - 1). Zo duidelijk, dit is onjuist. Je moet voet gevallen en dat soort dingen. Maar het idee hier is dat dit staart recursieve, wat betekent dat wanneer de belangrijkste gesprekken bar dat het gaat om de stack frame te krijgen. In deze stack frame er zal een kleine blok van het geheugen zijn dat overeenkomt met het argument x. En dus laten we zeggen de belangrijkste gebeurt te bellen bar (100); Dus x gaat beginnen als 100. Als de compiler erkent dat dit een staart recursieve functie, dan wanneer bar maakt zijn recursieve aanroep bar aan, plaats van een nieuwe stapel frame, dat is waar de stapel begint grotendeels groeien uiteindelijk zal lopen in de hoop en dan krijg je segfaults omdat het geheugen begint botsen. Dus in plaats van het maken van zijn eigen stack frame, kan het te realiseren, hey, ik heb nooit echt nodig om terug te komen op deze stapel frame, dus plaats ik zal gewoon vervangen dit argument met 99 en dan beginnen bar allemaal voorbij. En dan zal het opnieuw doen en het zal terug bar te bereiken (x - 1), en in plaats van het maken van een nieuwe stack frame, zal het gewoon vervangen de huidige argument met 98 en dan terug naar het begin van bar. Deze activiteiten, ter vervanging van dat 1 waarde op de stack en springen terug naar het begin, zijn vrij efficiënt. Dus niet alleen is dit hetzelfde geheugengebruik als een aparte functie die wordt iteratief omdat je alleen met behulp van een stack frame, maar je bent niet lijden onder de nadelen van het moeten functies aan te roepen. Belfuncties kan iets duurder, omdat het te maken heeft al deze setup en afbouw en al deze spullen. Dus dit staart recursie is goed. [Student] Waarom staat er geen nieuwe stappen? Omdat het beseft dat het niet nodig is. De oproep tot bar is net terug van de recursieve aanroep. Dus het hoeft niet om iets te doen met de return waarde. Het zal alleen maar om onmiddellijk terug te sturen. Dus het gaat gewoon om zijn eigen argumenten te vervangen en opnieuw te beginnen. En ook, als u niet beschikt over de staart recursieve versie, dan krijg je al die bars waar wanneer deze balk terug het heeft zijn waarde terug te keren naar deze ene, dan is dat bar onmiddellijk terug en het de waarde terug naar deze, dan is het gewoon om onmiddellijk terug te keren en terug te keren zijn waarde voor deze. Dus je bespaart dit popping al deze dingen af ​​van de stapel omdat de return waarde is gewoon te worden doorgegeven helemaal back-up toch. Dus waarom niet gewoon ter vervanging van onze discussie met de bijgewerkte argument en opnieuw beginnen? Als de functie niet staart recursieve, als je zoiets doen - [Student] als bar (x + 1). >> Ja. Dus als je het in staat, dan ben je iets te doen met de return waarde. Of zelfs als je gewoon terug 2 do * bar (x - 1). Nu bar (x - 1) moet terugkeren zodat het berekenen 2 maal deze waarde, dus nu is hoeft een eigen aparte stack frame, en nu, maakt niet uit hoe hard je ook probeert, je gaat nodig hebben om - Dit is niet de staart recursief. [Student] Zou ik proberen om een ​​recursie te brengen om te streven naar een staart recursie - [Bowden] In een ideale wereld, maar in CS50 u niet hoeft te doen. Met het oog op de staart recursie te krijgen, in het algemeen, stelt u een extra argument waar bar zal int x in y en y komt overeen met de ultieme wat je wilt om terug te keren. Dus dan is dit je gaat om terug te keren bar (x - 1), 2 * y. Dus dat is gewoon een high-level hoe je transformeren dingen om staart recursieve. Maar de extra argument - En dan op het einde als je je base case te bereiken, je gewoon terug y omdat je het verzamelen van de hele tijd dat de return waarde die u wilt. Je soort hebben gedaan het iteratief maar met behulp van recursieve oproepen. Vragen? [Student] Misschien over pointers, zoals bij het gebruik van strings. >> Tuurlijk. Pointers. Bij het gebruik van strings is het makkelijk omdat strings zijn char sterren, chars zijn voor eeuwig en altijd een enkele byte, en zo pointers is gelijk aan reguliere rekenen wanneer je te maken hebt met strijkers. Laten we zeggen dat char * s = "hello". Dus hebben we een blok in het geheugen. Het moet 6 bytes, want je moet altijd de null-terminator. En char * s gaat tot aan het begin van deze array. Dus s wijst er. Nu, dit is eigenlijk hoe een array werkt, ongeacht of het een rendement door malloc of dat het op de stapel. Een array is eigenlijk een pointer naar het begin van de array, en dan een array operatie, elke indexering, is gewoon in te gaan op die array een bepaalde offset. Dus toen ik iets als s [3] zeggen, dit gaat s en tellen 3 chars inch Dus s [3] Er zijn 0, 1, 2, 3, dus s [3] zal verwijzen naar dit l. [Student] En we konden bereiken dezelfde waarde door het doen van n + 3 en dan haakjes ster? Ja. Dit is gelijk aan * (s + 3); en dat is voor eeuwig en altijd gelijk maakt niet uit wat je doet. Je hoeft nooit aan de beugel syntax te gebruiken. U kunt altijd gebruik maken van de * (s + 3) syntaxis. Mensen hebben de neiging om de beugel syntaxis wilt, dat wel. [Student] Dus alle arrays zijn eigenlijk gewoon pointers. Er is een lichte onderscheid als ik zeg int x [4]; >> [student] Maakt dat maakt het geheugen? [Bowden] Dat gaat tot 4 ints te maken op de stapel, dus 16 bytes algemeen. Het gaat om 16 bytes te maken op de stapel. x nergens opgeslagen. Het is slechts een symbool met betrekking tot de start van het ding. Omdat je verklaarde de array binnenkant van deze functie, wat de compiler gaat doen is gewoon vervangen alle instanties van de variabele x met waar het is gebeurd om uit te kiezen om deze 16 bytes gezet. Het kan niet doen met char * s, want s is een echte pointer. Het is gratis te wijs andere dingen. x is een constante. Je kunt niet alles hebben punt naar een andere array. >> [Student] Oke. Maar dit idee, deze indexering, is dezelfde, ongeacht of het een traditioneel stelsel of als het een pointer naar iets of als het een pointer naar een malloced array. En in feite, het is zo gelijkwaardig dat dat ook is hetzelfde. Het is eigenlijk gewoon vertaalt wat er in de beugels en wat er van de beugels, voegt ze samen, en referentie aan. Dus dit is net zo geldig als * (s + 3) of s [3]. [Student] Kun je pointers wijzen naar 2-dimensionale arrays? Het is moeilijker. Traditioneel no. Een 2-dimensionale array bevindt zich op slechts een 1-dimensionale array met een aantal handige syntax want als ik zeg int x [3] [3], dit is echt maar 1 array met 9 waarden. En dus toen ik index, de compiler weet wat ik bedoel. Als ik zeg dat x [1] [2], weet ik wil naar de tweede rij, dus het gaat om de eerste 3 overslaan, en dan wil het tweede ding dat, dus het zal dit een te krijgen. Maar het is nog maar een single-dimensionale array. En dus als ik wilde een pointer toe te wijzen aan die array, Ik zou zeggen int * p = x; Het type van x is gewoon - Het is ruw te zeggen type x want het is gewoon een symbool en het is niet een echte variabele, maar het is gewoon een int *. x is slechts een wijzer naar het begin van deze. >> [Student] Oke. En dus ik zal niet in staat zijn om [1] [2] te openen. Ik denk dat er speciale syntax voor het declareren van een pointer, iets belachelijks als int (* p [-. iets absoluut belachelijk Ik weet niet eens. Maar er is een syntax voor de aangifte van pointers, zoals met haakjes en dingen. Het is misschien niet eens laten doen. Ik kon terug kijken naar iets dat zou me de waarheid vertellen. Later zullen voor, als er een syntax voor punt. Maar je zult het nooit zien. En zelfs de syntax zo archaïsch dat als je het gebruikt, mensen zullen verbijsterd. Multidimensionale arrays zijn vrij zeldzaam als het is. Je vrij veel - Nou, als je aan het doen bent matrix dingen dat het niet gaat als zeldzaam, maar in C je zelden gaat worden met behulp multidimensionale arrays. Ja. >> [Student] Laten we zeggen dat je een echt lange array. Dus in het virtuele geheugen het zou blijken te zijn alle opeenvolgende, als de elementen naast elkaar maar in het fysieke geheugen, zou het mogelijk zijn die worden opgesplitst? >> Ja. Hoe virtueel geheugen werkt is het scheidt gewoon - De eenheid van de toewijzing is een pagina, die de neiging heeft om 4 kilobytes, en dus als een proces zegt: hey, ik wil dit geheugen te gebruiken, het besturingssysteem gaat toewijzen is 4 kilobytes voor dat kleine blok van het geheugen. Zelfs als je alleen gebruik maken van een enkele kleine byte in het hele blok van het geheugen, het besturingssysteem zal geven van de volledige 4 kilobytes. Dus wat dit betekent is dat ik zou kunnen hebben - laten we zeggen dit is mijn stack. Deze stack kan worden gescheiden. Mijn stack kan megabytes en megabytes. Mijn stack kan enorm zijn. Maar de stapel zelf moet worden opgesplitst in afzonderlijke pagina's, die, als we kijken naar hier laten we zeggen dat dit is onze RAM, als ik 2 gigabyte aan RAM-geheugen, dit is de werkelijke adres 0 als de nulde byte van mijn RAM-geheugen, en dit is 2 gigabyte helemaal naar beneden hier. Dus deze pagina kan komen overeen met dit blok hier. Deze pagina kan overeenkomen met dit blok hier. Deze zou overeenkomen met deze hier. Dus het besturingssysteem is vrij om fysiek geheugen toe te wijzen aan een afzonderlijke pagina willekeurig. En dat betekent dat als deze grens overkomt straddle een array, een array toevallig links en rechts van deze van deze orde van een pagina dan die matrix zal worden gesplitst in het fysieke geheugen. En dan wanneer je stopt het programma, wanneer het proces eindigt, deze toewijzingen krijgen gewist en dan is het vrij om deze kleine blokken voor andere dingen gebruiken. Meer vragen? [Student] De aanwijzer rekenkunde. >> Oh ja. Snaren waren makkelijker, maar te kijken naar iets als ints, dus terug naar int x [4]; Of dit is een matrix of of het een pointer naar een malloced array van 4 gehele getallen, het gaat worden op dezelfde manier behandeld. [Student] Dus arrays zijn op de heap? [Bowden] Arrays zijn niet op de heap. >> [Student] Oh. [Bowden] Dit type array meestal op de stapel tenzij je verklaarde dat het bij - het negeren van globale variabelen. Gebruik geen globale variabelen. Binnenkant van een functie zeg ik int x [4]; Het gaat om een ​​4-integer blok op de stapel te maken voor dit array. Maar dit malloc (4 * sizeof (int)); zal gaan op de heap. Maar na dit punt kan ik gebruik maken van x-en p in vrijwel dezelfde manier, anders dan de uitzonderingen die ik al eerder zei over u kunt toewijzen p. Technisch gezien hun grootte zijn iets anders, maar dat is volkomen irrelevant. Je hebt nooit daadwerkelijk gebruik maken van hun maten. De p Ik zou kunnen zeggen p [3] = 2; of x [3] = 2; U kunt ze gebruiken op precies dezelfde manier. Dus pointers nu - Ja. [Student] Heb je niet te p * doen als je de haakjes? De beugels zijn een impliciete dereference. >> Oke. Eigenlijk, ook wat je zegt met de kunt u multidimensionale arrays met verwijzingen, wat je kunt doen is zoiets als, laten we zeggen, int ** pp = malloc (sizeof (int *) * 5); Ik zal gewoon schrijf alles eerst uit. Ik wilde niet dat die ene. Oke. Wat ik heb gedaan is hier - Dat moet pp [i]. Dus pp is een pointer naar een pointer. Je mallocing pp om te wijzen op een reeks van 5 int sterren. Dus in het geheugen heb je op de stapel pp Het gaat om te wijzen op een reeks van 5 blokken die allemaal zelf pointers. En toen ik malloc hier beneden, ik malloc dat elk van deze individuele pointers moet verwijzen naar een apart blok van 4 bytes op de heap. Dus dit wijst op 4 bytes. En dit wijst op een andere 4 bytes. En allemaal punt van hun eigen 4 bytes. Dit geeft mij een manier van doen multidimensionale dingen. Ik zou kunnen zeggen pp [3] [4], maar nu is dit niet hetzelfde als multidimensionale arrays multidimensionale arrays omdat het vertaald [3] [4] in een verschuiving in de x array. Deze referentie aan p, toegang tot de derde-index, dan referentie aan dat en toegangen - 4 zou ongeldig zijn - de tweede index. Overwegende dat, wanneer we de int x [3] [4] voor als een multidimensionale array en wanneer u dubbelklikt beugel het is echt slechts een dereference, je volgt een pointer en dan een offset, dit is echt 2D referenties. Je volgt 2 aparte pointers. Dus dit ook technisch stelt u in staat om multidimensionale arrays waarbij elk array verschillende maten. Dus ik denk dat gekartelde multidimensionale arrays is hoe het heet Sinds echt het eerste wat zou kunnen wijzen op iets dat 10 elementen heeft, de tweede wat zou kunnen wijzen op iets dat 100 elementen heeft. [Student] Is er een limiet aan het aantal aanwijzingen kunt u verwijzen naar andere pointers? >> Nee. U kunt int ***** p. Terug naar pointers - >> [student] Oh. >> Ja. [Student] Als ik int *** p en dan doe ik een dereferentie en ik zeg p * gelijk is aan deze waarde, is het alleen maar om 1 niveau van dereferentie doen? >> Ja. Dus als ik wil het ding dat de laatste wijzer wijst naar toegang - Dan doe je *** p. >> Oke. Dit is dus p wijst naar een blok, verwijst naar een ander blok, wijst naar een ander blok. Dan als je dat doet * p = iets anders, dan bent u het wijzigen van deze nu verwijzen naar een ander blok. >> Oke. [Bowden] En als deze werden malloced, dan heb je nu gelekt geheugen tenzij je toevallig verschillende referenties van deze hebben want je kunt niet terug naar die degenen die je gewoon weggegooid. Pointers. int x [4], zal een array van 4 integers toewijzen waarbij x gaat tot aan het begin van de array. Dus als ik zeg iets als x [1], ik wil dat het naar de tweede geheel getal in de array gaan betekenen, die deze men. Maar echt, dat is 4 bytes in de array, omdat dit getal neemt 4 bytes. Dus een offset van 1 betekent echt een offset van 1 keer zo groot, ongeacht het type van de matrix. Dit is een array van integers, zodat het weet te doen 1 keer groot int wanneer het wil offset. De andere syntax. Bedenk dat deze gelijk is aan * (x + 1); Als ik zeg pointer + 1, wat dat terugkeert is het adres dat de aanwijzer wordt het opslaan van plus 1 maal de grootte van het type pointer. Dus als x = ox100, dan is x + 1 = ox104. En je kunt misbruiken en zeggen iets als char * c = (char *) x; en nu c gaat naar hetzelfde adres als x. c gaat gelijk aan ox100, maar c + 1 gaat gelijk aan ox101 aangezien pointers afhankelijk van het type van de pointer die u toevoegt. Dus c + 1, het ziet er bij c, het is een char pointer, dus het gaat om 1 keer grootte van char toe te voegen, die altijd zal zijn 1, dus je krijgt 101, dat als ik x, die ook nog 100, x + 1 gaat worden 104. [Student] Kun je met c + + om de aanwijzer te bevorderen door 1? Ja, dat kan. Je kunt dat niet doen met x, want x is slechts een symbool, het is een constante, je kunt niet veranderen x. Maar c gebeurt er gewoon een pointer, dus c + + is perfect geldig en het zal verhogen met 1. Als c waren gewoon een int *, dan is c + + zou worden 104. + + Doet pointers net als c + 1 zou hebben gedaan pointers. Dit is eigenlijk hoe een heleboel dingen, zoals merge sort - In plaats van het creëren van kopieën van de dingen, kunt u in plaats daarvan gaan - Net als ik wilde deze helft van de array voorbij - is wis enkele van deze te laten. Laten we zeggen dat ik wilde deze kant van de array overgaan in een functie. Wat zou ik doorgeven aan die functie? Als ik voorbij x, ik ben het passeren van dit adres. Maar ik wil dit bijzondere adres passeren. Dus wat moet ik gaan? [Student] Pointer + 2? [Bowden] Dus x + 2. Ja. Dat gaat naar dit adres te zijn. U zult ook heel vaak zien als x [2] en vervolgens het adres van dat. Dus je moet het adres van te nemen, omdat de beugel is een impliciete dereference. x [2] verwijst naar de waarde die in dit vak, en dan wil je het adres van die doos, dus je zegt en x [2]. Dus dat is hoe iets in merge sort waar u de helft van de lijst door te geven aan iets je echt gewoon voorbij en x [2], en nu voor zover de recursieve aanroep betreft, mijn nieuwe array begint daar. Last minute vragen. [Student] Als we niet plaatsen een ampersand of - wat is dat genoemd? >> Star? [Student] Star. >> Technisch dereference operator, maar - >> [student] dereference. Als we niet plaatsen een ster of een teken, wat gebeurt er als ik alleen maar zeggen y = x en x is een pointer? Wat is het type y? >> [Student] ik zal gewoon zeggen dat het wijzer 2. Dus als je gewoon zeggen y = x, nu x en y wijzen op hetzelfde. >> [Student] Punt op hetzelfde neer. En als x een int pointer? >> Het zou klagen, want je kunt niet toewijzen pointers. [Student] Oke. Vergeet niet dat pointers, ook al hebben we ze te tekenen als pijlen, echt alles wat ze winkel - int * x - echt alle x is het opslaan is zoiets als ox100, die we toevallig voor te stellen als die naar het blok opgeslagen bij 100. Dus als ik zeg int * y = x, ik ben gewoon het kopiëren van ox100 in y, die we gaan gewoon te vertegenwoordigen als y, ook wijzend naar ox100. En als ik zeg int i = (int) x, dan ik zal slaan ongeacht de waarde van ox100 is binnenkant van het, maar nu gaat worden geïnterpreteerd als een geheel getal in plaats van een pointer. Maar je moet de cast of anders zal klagen. [Student] Dus bedoel je te werpen - Gaat het te gieten int van x of gieten int van y? [Bowden] Wat? [Student] Oke. Na deze haakjes wordt er zullen een x of ay daar? [Bowden] Ofwel. x en y zijn equivalent. >> [Student] Oke. Omdat ze beide pointers. >> Ja. [Student] Dus het zou slaan de hexadecimale 100 in getal vorm? >> [Bowden] Ja. Maar niet de waarde van wat het verwijst. [Bowden] Ja. >> [Student] Dus gewoon het adres in integer vorm. Oke. [Bowden] Als je wilde voor een aantal bizarre reden, je zou kunnen uitsluitend met pointers en nooit te gaan met gehele getallen en net zijn als int * x = 0. Dan zul je echt in de war raken wanneer pointers begint gebeurt. Dus de nummers die ze slaan zijn zinloos. Het is gewoon hoe je uiteindelijk de interpretatie ervan. Dus ik ben vrij om te ox100 kopiëren van een int * naar een int, en ik ben vrij om toe te wijzen - waarschijnlijk gaat krijgen schreeuwde naar voor niet gieten Je bent - Ik ben vrij om iets toe te wijzen als (int *) ox1234 in deze willekeurige int *. Dus ox123 is net zo geldig een geheugenadres zoals & y. & Y gebeurt om terug te keren iets dat is vrij veel ox123. [Student] Zou dat echt een leuke manier om te gaan van hexadecimaal naar decimaal vorm, graag als je een pointer en je wierp het als een int? [Bowden] U kunt eigenlijk gewoon afdrukken met als printf. Laten we zeggen dat ik int y = 100. Dus printf (% d \ n - zoals u al zou moeten weten - druk dat als een geheel getal,% x. We zullen gewoon af te drukken als hexadecimale. Dus een pointer wordt niet opgeslagen als hexadecimale, en een geheel getal wordt niet opgeslagen als decimale. Alles wordt opgeslagen als binaire. Het is gewoon dat we de neiging om pointers als hexadecimale tonen omdat we denken dat de dingen in deze 4-byte blokken, en geheugen adressen hebben de neiging om op de hoogte. We zijn net als het begint met bf, dan gebeurt het om op de stapel. Dus het is gewoon onze interpretatie van pointers als hexadecimale. Oke. Elke laatste vragen? Ik zal er zijn voor een beetje na als je iets anders. En dat is het einde van die. [Student] Yay! [Applaus] [CS50.TV]