[Powered by Google Translate] [Afsnit 4 - Mere behagelig]
[Rob Bowden - Harvard University]
[Dette er CS50. - CS50.TV]
Vi har en quiz i morgen, hvis du fyre ikke vide det.
Det er dybest set på alt hvad du kunne have set i klassen eller skulle have set i klassen.
Det omfatter pegepinde, selvom de er en meget nylige emne.
Du bør i det mindste forstå de høje niveauer af dem.
Alt, hvad der var gået over i klassen, bør du forstå for quizzen.
Så hvis du har spørgsmål om dem, kan du bede dem nu.
Men det vil være en meget elev-ledede session, hvor du fyre stille spørgsmål,
så forhåbentlig folk har spørgsmål.
Er der nogen der har spørgsmål?
Ja. >> [Studerende] Kan du gå over pointers igen?
Jeg vil gå over pegepinde.
Alle dine variabler nødvendigvis bor i hukommelsen,
men normalt behøver du ikke bekymre dig om det, og du bare sige x + 2 og y + 3
og compileren vil regne ud, hvor tingene lever for dig.
Når du har at gøre med pointere, nu er du eksplicit vha. disse hukommelse adresser.
Så en enkelt variabel vil kun nogensinde bo på en enkelt adresse på et givet tidspunkt.
Hvis vi ønsker at erklære en pegepind, hvad den type kommer til at se ud?
>> Jeg vil gerne erklære en pointer p. Hvad betyder den type ud?
[Studerende] int * p. >> Yeah. Så int * p.
Og hvordan gør jeg det peger på x? >> [Studerende] Ampersand.
[Bowden] So-tegn er bogstaveligt talt kaldes adresse operatør.
Så når jeg siger & x det bliver lageradressen af ​​den variable x.
Så nu har jeg markøren p, og hvor som helst i min kode jeg kan bruge * p
eller jeg kunne bruge x, og det vil være præcis de samme ting.
(* P). Hvad er dette gør? Hvad betyder det stjerne betyde?
[Studerende] Det betyder en værdi på det tidspunkt. >> Yeah.
Så hvis vi ser på det, kan det være meget nyttigt at trække de diagrammer
hvor dette er en lille kasse med hukommelse for x, som tilfældigvis har værdien 4,
så har vi en lille kasse med hukommelse for p,
og så p peger på x, så trækker vi en pil fra p til x.
Så når vi siger * p vi siger gå til den boks, der er p.
Star er følg pilen, og derefter gøre hvad du vil med denne boks lige der.
Så jeg kan sige * p = 7, og som vil gå til den boks, der er x og forandring, til 7.
Eller jeg kunne sige int z = * p * 2, det er forvirrende, fordi det er stjerne, stjerne.
Den ene stjerne er dereferere p, er den anden stjerne gange med 2.
Bemærk, at jeg kunne have lige så godt erstattet * p med x.
Du kan bruge dem på samme måde.
Og så senere jeg kan få p peger på en helt ny ting.
Jeg kan bare sige p = &z;
Så nu P ikke længere peger på x, og det peger på z.
Og helst jeg gør * p det er det samme som at gøre z.
Så det nyttige ting om dette er, når vi begynder at komme ind i funktioner.
>> Det er lidt nytteløst at erklære en pegepind, der peger på noget
og så er du bare dereferere det
når du kunne have brugt den oprindelige variabel til at begynde med.
Men når du kommer ind i funktioner - så lad os sige, at vi har nogle funktion, int foo,
der tager en pointer og bare gør * p = 6;
Ligesom vi så før med swap, kan du ikke gøre en effektiv swap og en særskilt funktion
ved blot passerer heltal fordi alt i C altid er forbi værdi.
Selv når du passerer pointers du passerer i værdi.
Det er bare sådan, at disse værdier er hukommelse adresser.
Så når jeg siger foo (p), jeg passerer markøren ind i funktionen Foo
og derefter Foo gør * p = 6;
Så indersiden af ​​denne funktion, er * p stadig svarer til x,
men jeg kan ikke bruge x indersiden af ​​denne funktion, da det ikke er scoped inden for denne funktion.
Så * p = 6 er den eneste måde jeg kan få adgang til en lokal variabel fra en anden funktion.
Eller, ja, pointers er den eneste måde jeg kan få adgang til en lokal variabel fra en anden funktion.
[Studerende] Lad os sige at du ville returnere en pegepind. Hvordan præcist gør man det?
[Bowden] Returner en pointer som i noget lignende int y = 3; afkast & y? >> [Studerende] Yeah.
[Bowden] Okay. Du bør aldrig gøre det. Det er skidt.
Jeg tror jeg så i disse forelæsninger dias du begyndte at se hele denne diagram af hukommelse
hvor op her du har fået hukommelse adresse 0
og hernede har du hukommelsesadressekonstanter 4 gigs eller 2 til 32.
Så du har fået nogle ting og nogle ting og så har du din stack
og du har fået din bunke, som du lige er begyndt at lære om, at vokse op.
[Studerende] Er ikke den bunke oven i stakken?
>> Yeah. Den bunke er på toppen, er det ikke? >> [Studerende] Nå, han lagde 0 på toppen.
[Studerende] Åh, han satte 0 på toppen. >> [Studerende] Åh, okay.
Disclaimer: Anywhere med CS50 du kommer til at se det på denne måde. >> [Studerende] Okay.
Det er bare, at når du først ser stakke,
ligesom når du tænker på en stak du tænker på at stable ting oven på hinanden.
Så vi har en tendens til at vende dette rundt, så stakken vokser op som en stak normalt ville
stedet for stablen hænger ned. >> [Studerende] ikke dynger teknisk vokse op for, selvom?
Det afhænger af hvad du mener med at vokse op.
Stakken og heap altid vokse i modsatte retninger.
En stak er altid vokser op i den forstand, at det vokser op
mod højere hukommelse adresser, og bunke vokser ned
i at det vokser i retning af lavere hukommelse adresser.
Så toppen er 0, og bunden er høj hukommelse adresser.
De er begge stadig, bare i modsatte retninger.
[Studerende] Jeg mente bare, at fordi du sagde, du lægger stakken på bunden
fordi det forekommer mere intuitivt grund for stakken at starte på toppen af ​​en bunke,
bunke er oven på sig selv også, så that's - >> Yeah.
Du kan også tænke på bunke som vokser op og større, men stakken mere så.
Så stakken er den, vi slags ønsker at vise vokse op.
Men overalt du ser ellers vil vise adresse 0 øverst
og den højeste hukommelse adressen nederst, så dette er din sædvanlige billede af hukommelsen.
>> Har du et spørgsmål?
[Studerende] Kan du fortælle os mere om bunke?
Yeah. Jeg kommer til om et øjeblik.
Først går tilbage til hvorfor returnering & y er en dårlig ting,
på stakken du har en masse stakrammer, som repræsenterer alle de funktioner
der er blevet kaldt.
Så ignorerer tidligere ting er toppen af ​​din stack altid vil være den primære funktion
da det er den første funktion, der bliver kaldt.
Og så når du kalder en anden funktion, er stakken vil vokse ned.
Så hvis jeg kalder en funktion, foo, og det får sin egen stakramme,
den kan kalde en funktion, bar, det får sin egen stakramme.
Og bar kunne være rekursiv, og det kunne kalde sig,
og således at andet opkald til bar vil få sin egen stakramme.
Og så hvad der går i disse stakrammer er alle de lokale variable
og alle de funktionsargumenter at -
Eventuelle ting, der er lokalt scoped til denne funktion gå i disse stakrammer.
Så det betyder, når jeg sagde noget i retning bar er en funktion,
Jeg skal bare til at erklære et heltal og derefter returnere en pegepind til denne heltal.
Så hvor kommer y bor?
[Studerende] y bor i bar. >> [Bowden] Yeah.
Et sted i denne lille firkant af hukommelse er en littler firkant, der har y i det.
Når jeg vender tilbage & Y, jeg returnerer en pointer til denne lille blok af hukommelse.
Men så når en funktionen returnerer, bliver dens stakramme poppet fra stakken.
Og det er derfor, det hedder stakken.
Det er ligesom stakken datastruktur, hvis du ved hvad det er.
Eller endda som en stak af bakker er altid eksempel,
main kommer til at gå på bunden, så den første funktion du kalder kommer til at gå på toppen af ​​det,
og du kan ikke komme tilbage til main indtil du vender tilbage fra alle funktioner, der er blevet kaldt
som er blevet anbragt oven på den.
>> [Studerende] Så hvis du gjorde gøre returnere & y, at værdien kan ændres uden varsel.
Ja, det er - >> [studerende] Det kunne være overskrevet. >> Yeah.
Det er helt - Hvis du prøver og -
Dette ville også være en int * bar fordi det returnerer en pointer,
så dens returtype er int *.
Hvis du forsøger at bruge returværdien af ​​denne funktion, er det udefineret adfærd
fordi denne pegepind peger på dårlig hukommelse. >> [Studerende] Okay.
Så hvad nu hvis, for eksempel, erklærede du int * y = malloc (sizeof (int))?
Det er bedre. Ja.
[Studerende] Vi talte om, hvordan når vi trækker ting til vores papirkurven
de er faktisk ikke slettet, vi skal bare miste deres pointers.
Så i dette tilfælde har vi faktisk slette værdien, eller er det stadig i hukommelsen?
For det meste, det vil stadig være der.
Men lad os sige, at vi tilfældigvis kalde en anden funktion, baz.
Baz kommer til at få sin egen stakramme på her.
Det kommer til at blive overskrive alle disse ting,
og derefter, hvis du senere forsøge at bruge markøren som du fik før,
det kommer ikke til at være den samme værdi.
Det kommer til at have ændret sig, bare fordi du kaldte funktionen Baz.
[Studerende] Men havde vi ikke, ville vi stadig få 3?
[Bowden] Efter al sandsynlighed ville du.
Men du kan ikke stole på det. C bare siger udefineret adfærd.
>> [Studerende] Åh, det gør. Okay.
Så når du ønsker at returnere en pegepind, er det her malloc kommer i brug.
Jeg skriver faktisk bare returnere malloc (3 * sizeof (int)).
Vi vil gå over malloc mere i en anden, men tanken om malloc er alle dine lokale variable
altid gå på stakken.
Alt, hvad der er malloced går på bunke, og det vil for evigt og altid være på heapen
indtil du eksplicit frigøre det.
Så det betyder, at når du malloc noget, det kommer til at overleve efter funktionen returnerer.
[Studerende] Vil det overleve, når programmet stopper? >> Nej.
Okay, så det kommer til at være der, indtil programmet er helt færdig kører. >> Ja.
Vi kan gå over oplysninger om, hvad der sker, når programmet stopper.
Du skal muligvis til at minde mig, men det er en særskilt ting helt.
[Studerende] So malloc skaber en pointer? >> Yeah.
Malloc - >> [studerende] Jeg tror malloc betegner en blok af hukommelse, en pegepind kan bruge.
[Bowden] Jeg ønsker at diagrammet igen. >> [Studerende] Så denne funktion virker, selvom?
[Studerende] Yeah, malloc betegner en blok af hukommelse, som du kan bruge,
og derefter returnerer adressen på den første blok i denne hukommelse.
>> [Bowden] Yeah. Så når du malloc, du snuppe nogle blok af hukommelse
Det er i øjeblikket i bunke.
Hvis bunke er for lille, så den bunke er bare at vokse, og den vokser i denne retning.
Så lad os sige den bunke er for lille.
Så det handler om at vokse en lille smule og returnere en pegepind til denne blok, der bare voksede.
Når du gratis ting, du gør mere plads i bunke,
så derefter en senere kald til malloc kan genbruge denne hukommelse, som du tidligere havde befriet.
Det vigtige ved malloc og gratis er, at det giver dig fuld kontrol
over levetiden for disse hukommelsesblokke.
Globale variabler er altid i live.
Lokale variabler er i live inden for deres rækkevidde.
Så snart du går forbi en klammeparentes, de lokale variable er døde.
Malloced hukommelse er i live, når du ønsker det at være i live
og derefter frigives, når du fortæller det til at blive frigivet.
Det er faktisk de eneste 3 typer af hukommelse, virkelig.
Der er automatisk hukommelse forvaltning, hvilket er stakken.
Tingene sker automatisk for dig.
Når du siger int x, hukommelse afsat til int x.
Når x går ud af rækkevidde, er hukommelsen regenereret for x.
Så er der dynamisk hukommelse ledelse, hvilket er hvad malloc er,
der er, når du har kontrol.
Du dynamisk beslutte, hvornår hukommelsen bør og ikke bør tildeles.
Og så er der statisk, hvilket betyder blot, at den lever for evigt,
hvilket er, hvad globale variabler.
De er bare altid i hukommelsen.
>> Spørgsmål?
[Studerende] Kan du definere en blok blot ved hjælp af krøllede parenteser
men ikke behøver at have en if-sætning eller et stykke erklæring eller noget i den retning?
Du kan definere en blok som i en funktion, men som har krøllede parenteser også.
[Studerende] Så du kan ikke bare have som en tilfældig par krøllede parenteser i din kode
der har lokale variabler? >> Ja, du kan.
Inside of int bar vi kunne have {int y = 3;}.
Det er meningen at være lige her.
Men det er helt definerer omfanget af int y.
Efter denne anden klammeparentes, kan y ikke bruges længere.
Du næsten aldrig gøre det, selv om.
Kom tilbage til, hvad der sker, når et program slutter,
Der er lidt af en misforståelse / halv løgn, at vi giver, for at bare gøre tingene lettere.
Vi fortæller dig, at når du allokere hukommelse
du afsætte nogle bid af RAM for denne variabel.
Men du er ikke rigtig direkte berøring RAM nogensinde i dine programmer.
Hvis du tænker over det, hvordan jeg gjorde -
Og faktisk, hvis du går gennem i GDB du vil se det samme.
Uanset hvor mange gange du kører dit program eller hvilket program, du kører,
stakken vil altid starte -
du altid kommer til at se variabler omkring adresse oxbffff noget.
Det er normalt et sted i denne region.
Men hvordan kan 2 programmer muligvis have henvisninger til den samme hukommelse?
[Studerende] Der er nogle vilkårlige udpegning af hvor oxbfff formodes at være på RAM
der rent faktisk kan være forskellige steder afhængigt af, når funktionen blev kaldt.
Yeah. Udtrykket er virtuel hukommelse.
Ideen er, at hver enkelt proces, hver eneste program, der kører på din computer
har sin egen - lad os antage 32 bit - helt uafhængig adresse plads.
Dette er den adresse rummet.
Det har sine egne helt uafhængige 4 gigabyte til at bruge.
>> Så hvis du kører 2 programmer samtidigt, dette program ser 4 gigabyte til sig selv,
dette program ser 4 gigabyte til sig selv,
og det er umuligt for dette program at dereference en pegepind
og ender med hukommelse fra dette program.
Og hvad virtuel hukommelse er er en kortlægning fra et processer adresse rum
til de faktiske ting på RAM.
Så det er op til dit operativsystem for at vide,
hey, når denne fyr dereferences pointer oxbfff, der virkelig betyder
at han ønsker RAM byte 1000,
hvorimod hvis dette program dereferences oxbfff, han virkelig ønsker RAM byte 10000.
De kan være vilkårligt langt fra hinanden.
Dette er endda tilfældet med tingene inden for en enkelt processer adresse rummet.
Så ligesom det ser alle 4 gigabyte til sig selv, men lad os sige -
[Studerende] Har hver enkelt proces -
Lad os sige du har en computer med kun 4 GB RAM.
Har hver enkelt proces se hele 4 gigabyte? >> Ja.
Men de 4 gigabyte den ser er en løgn.
Det er bare det mener, at det har alt dette hukommelsen, fordi den ikke kender nogen anden proces eksisterer.
Det vil kun bruge så meget hukommelse, som den faktisk har brug for.
Operativsystemet er ikke vil give RAM til denne proces
hvis det ikke bruger nogen hukommelse i hele denne region.
Det kommer ikke til at give det hukommelsen for denne region.
Men ideen er, at - Jeg forsøger at tænke på - jeg kan ikke tænke på en analogi.
Analogier er hårdt.
Et af de spørgsmål virtuel hukommelse eller en af ​​de ting det er at løse
er, at processer bør være helt klar over hinanden.
Og så du kan skrive et program, der bare dereferences nogen pointer,
gerne bare skrive et program, der siger * (ox1234),
og det er dereferere hukommelse adresse 1234.
>> Men det er op til det operativsystem, der derefter oversætte hvad 1234 betyder.
Så hvis 1234 sker for at være en gyldig hukommelse adresse til denne proces,
ligesom det er på stakken eller noget, så vil dette returnere værdien af ​​at hukommelsen adresse
for så vidt angår fremgangsmåden, ved.
Men hvis 1234 er ikke en gyldig adresse, ligesom det sker at lande
i nogle lille stykke af hukommelse, som ligger hinsides stakken og ud over dyngen
og du har ikke rigtig brugt det, så det er når du får ting som segfault'er
fordi du rører hukommelse, som du ikke bør røre.
Det er også sandt -
En 32-bit system, 32 bit betyder, at du har 32 bits til at definere en hukommelse adresse.
Det er derfor, pegepinde er 8 bytes, fordi 32 bit er 8 bytes - eller 4 bytes.
Pointers er 4 bytes.
Så når du ser en pegepind som oxbfffff, der er -
Inden et givent program kan du bare konstruere en vilkårlig pointer,
hvor som helst fra ox0 til ox 8 f's - FFFFFFFF.
[Studerende] Sagde du ikke, de er 4 byte? >> Yeah.
[Studerende] Så hver byte vil have - >> [Bowden] Hexadecimal.
Hexadecimal - 5, 6, 7, 8. Så pointers du vil altid se i hexadecimal.
Det er bare hvordan vi klassificerer pointers.
Hver 2 cifre af hexadecimal er 1 byte.
Så der kommer til at være 8 hexadecimale cifre til 4 bytes.
Så hver eneste markør på en 32-bit system vil være 4 byte,
hvilket betyder, at din proces kan du konstruere vilkårlige 4 byte
og lave en pointer ud af det,
hvilket betyder, at så vidt det er bekendt, kan den afgive en hel 2 til 32 bytes hukommelse.
Selvom det ikke rigtig har adgang til det,
selvom din computer kun har 512 megabyte, men mener, det har så meget hukommelse.
Og operativsystemet er smart nok, at det kun vil tildele hvad du rent faktisk har brug for.
Det er ikke bare gå, åh, en ny proces: 4 gigs.
>> Yeah. >> [Studerende] Hvad betyder okse betyde? Hvorfor skriver du det?
Det er bare et symbol for hexadecimal.
Når du ser et nummer starter med okse, de successive ting er hexadecimal.
[Studerende] Du var forklare om, hvad der sker, når et program slutter. >> Ja.
Hvad sker der, når et program slutter, er operativsystemet
bare sletter kortlægninger, at det har for disse adresser, og det er det.
Operativsystemet kan nu nøjes med at give denne hukommelse til et andet program til at bruge.
[Elev] Okay.
Så når du allokere noget på heapen eller de stak eller globale variabler eller noget,
de alle bare forsvinde, så snart programmet slutter
da operativsystemet er nu fri til at give denne hukommelse til enhver anden proces.
[Studerende] Selvom der er sandsynligvis stadig værdier skrevet i? >> Yeah.
Værdierne er sandsynligvis stadig.
Det er bare det vil være vanskeligt at få ram på dem.
Det er meget sværere at få ram på dem, end det er at komme på en slettet fil
fordi den slettede fil slags sidder der i lang tid, og harddisken er en meget større.
Så det kommer til at overskrive forskellige dele af hukommelsen
før det sker at overskrive bid af hukommelse, denne fil bruges til at være på.
Men hovedlager, RAM, du bladre gennem en hel del hurtigere,
så det kommer til at meget hurtigt blive overskrevet.
Spørgsmål til dette eller noget andet?
[Studerende] Jeg har spørgsmål om et andet emne. >> Okay.
Er der nogen der har spørgsmål om dette?
>> Okay. Andet emne. >> [Studerende] Okay.
Jeg gik gennem nogle af de praksis tests,
og i en af ​​dem det talte om sizeof
og den værdi, den returnerer eller forskellige variable typer. >> Ja.
Og det siges, at både int og lang både tilbagevenden 4, så de er begge 4 byte lang.
Er der nogen forskel mellem en int og en lang, eller er det det samme?
Ja, der er en forskel.
The C standard -
Jeg er nok kommer til at rod op.
C-standard er ligesom hvad C er den officielle dokumentation C.
Dette er, hvad det siger.
Så C standard bare siger, at en char vil for evigt og altid være 1 byte.
Alt efter, at - en kort er altid lige defineres som værende større end eller lig med en char.
Dette kan være strengt større end, men ikke positiv.
En int er lige defineres som værende større end eller lig med en kort.
Og et langt er netop defineret som værende større end eller lig med en int.
Og en lang lang er større end eller lig med lang.
Så det eneste, C standarden definerer, er den relative rækkefølge af alt.
Den faktiske mængde hukommelse, ting tager op er almindeligvis op til gennemførelsen,
men det er temmelig godt defineret på dette punkt. >> [Studerende] Okay.
Så shorts er næsten altid vil være 2 byte.
Ints er næsten altid vil være 4 byte.
Lange længes næsten altid vil være 8 byte.
Og længes, det afhænger af, om du bruger en 32-bit eller en 64-bit system.
Så længe vil svare til den type system.
Hvis du bruger en 32-bit system som Appliance, går det at være 4 byte.
Hvis du bruger en 64-bit som en masse af de seneste computere, går det at være 8 bytes.
>> Ints er næsten altid 4 byte på dette punkt.
Lange længes er næsten altid 8 bytes.
I fortiden, brugte int'er kun være 2 bytes.
Men bemærk, at denne helt opfylder alle disse relationer er større end og lig med.
Så længe er perfekt lov til at være samme størrelse som et helt tal,
og det er også tilladt at være den samme størrelse som en lang lang.
Og det bare så sker for at være, at der i 99,999% af systemerne, er det vil være lig med
enten en int eller en lang lang. Det bare afhænger af 32-bit eller 64-bit. >> [Studerende] Okay.
I flåd, er, hvordan decimaltegnet udpeget i form af bits?
Ligesom som binær? >> Yeah.
Du behøver ikke at vide, at for CS50.
Du behøver ikke engang lære, at i 61.
Du behøver ikke lære at virkelig i ethvert kursus.
Det er bare en repræsentation.
Jeg glemmer de eksakte bit kolonihaver.
Ideen med flydende punkt er, at man afsætter et bestemt antal bit til at repræsentere -
Dybest set, alt er i videnskabelig notation.
Så du tildele et bestemt antal bits til at repræsentere selve nummeret, ligesom 1,2345.
Jeg kan aldrig repræsentere et tal med flere cifre end 5.
Så kan du også tildele et bestemt antal bits, så det har en tendens til at være ligesom
du kan kun gå op til et vist antal, ligesom det er den største eksponent du kan have,
og du kan kun gå ned til en vis eksponent,
gerne, der er den mindste eksponent du kan have.
>> Jeg kan ikke huske den præcise måde bits er tildelt til alle disse værdier,
men et vist antal bit er dedikeret til 1,2345,
andet bestemt antal bits er dedikeret til eksponent,
og det er kun muligt at repræsentere en eksponent for en vis størrelse.
[Studerende] Og en dobbelt? Er det ligesom en ekstra lang float? >> Yeah.
Det er det samme som en float undtagen nu du bruger 8 bytes i stedet for 4 byte.
Nu vil du være i stand til at bruge 9 cifre eller 10 cifre,
og dette vil være i stand til at gå op til 300 i stedet for 100. >> [Studerende] Okay.
Og flåd er også 4 bytes. >> Ja.
Nå, igen, det afhænger nok overall den generelle gennemførelse,
men flåd er 4 bytes, doubler er 8.
Doubles kaldes dobbelt, fordi de er dobbelt størrelse af flåd.
[Elev] Okay. Og er der dobbelt fordobler? >> Der er ikke.
Jeg tror - >> [studerende] Kan du lide lange længes? >> Yeah. Det tror jeg ikke. Ja.
[Studerende] Den sidste års test var der et spørgsmål om den primære funktion
skulle være en del af dit program.
Svaret var, at det ikke behøver at være en del af dit program.
I hvilken situation? Det er, hvad jeg så.
[Bowden] Det synes - >> [studerende] Hvad situation?
Har du problemet? >> [Studerende] Ja, jeg kan helt sikkert trække det op.
Det behøver ikke at være teknisk, men dybest set er det kommer til at være.
[Studerende] Jeg så en på et andet år.
Det var ligesom Sandt eller falsk: Et gyldigt - >> Åh, en c-fil.?
. [Studerende] Enhver c-filen skal have - [både taler på én gang - uforståelig]
Okay. Så det er adskilt.
>> A. C. fil bare nødt til at indeholde funktioner.
Du kan udarbejde en fil til maskinkode, binær, uanset,
uden at det er eksekverbar endnu.
En gyldig eksekverbar skal have en hovedfunktion.
Du kan skrive 100 funktioner i 1 fil, men ingen vigtigste
og derefter kompilere at ned til binær,
så skriver du en anden fil, der kun har main men det kræver en masse af disse funktioner
i denne binære fil herovre.
Og så når du laver den eksekverbare, det er hvad linkeren gør
er det kombinerer disse 2 binære filer til en eksekverbar.
Så en. C. fil behøver ikke at have en hovedfunktion på alle.
Og på store kodebaser du vil se tusindvis af. C-filer og 1 vigtigste fil.
Flere spørgsmål?
[Studerende] Der var et andet spørgsmål.
Det sagde gøre er en compiler. Sandt eller falsk?
Og svaret var forkert, og jeg forstod, hvorfor det er ikke ligesom Dunk.
Men hvad gør vi kalder gøre, hvis det ikke er?
Gør er dybest set bare - jeg kan se præcis, hvad den kalder det.
Men det bare kører kommandoer.
Gør.
Jeg kan trække det op. Yeah.
Oh, yeah. Gør også gør det.
Det siger formålet med make nytte er automatisk at afgøre
hvilke dele af et stort program som behøver at blive genoversat
og udstede kommandoer til at genoversætte dem.
Du kan gøre lave filer, der er absolut enorm.
Gør ser på tidsstempler af filer, og ligesom vi sagde før,
du kan kompilere individuelle filer ned, og det er ikke før du kommer til linkeren
at de er sat sammen til en eksekverbar.
Så hvis du har 10 forskellige filer, og du foretager en ændring til 1 af dem,
så hvad gør vil gøre er bare rekompilere at 1 fil
og derefter sammenlænke alt sammen.
Men det er meget dummere end det.
Det er op til dig at helt definere, at det er, hvad det skal gøre.
Det som standard har evnen til at genkende denne tidsstempel stuff,
men du kan skrive en make-fil til at gøre noget.
Du kan skrive en make fil, så når du skriver at gøre det bare cd'er til en anden mappe.
Jeg var ved at blive frustreret, fordi jeg tack alt inde i mit Appliance
og så vil jeg se PDF fra Mac.
>> Så jeg går til Finder og jeg kan gøre Go, forbindelse til server,
og serveren jeg forbindelse til, er min Appliance, og så åbner jeg op for PDF
der bliver udarbejdet af LaTeX.
Men jeg var ved at blive frustreret, fordi hver eneste gang jeg havde brug for at opdatere PDF,
Jeg var nødt til at kopiere det til en bestemt mappe, at det kunne få adgang til
og det var at få irriterende.
Så i stedet skrev jeg en make-fil, som du er nødt til at definere, hvordan det gør tingene.
Hvordan du gør i dette er PDF LaTeX.
Ligesom enhver anden make-fil - eller jeg gætte, du ikke har set de gøre filer,
men vi har i Appliance en global make-fil, der bare siger,
hvis du kompilerer en C-fil, skal du bruge Dunk.
Og så her i min make-fil, som jeg gør jeg siger,
denne fil, du vil ønsker at kompilere med PDF LaTeX.
Og så det er PDF LaTeX, der laver den kompilering.
Gør ikke kompilering. Det er bare at køre disse kommandoer i rækkefølge jeg angav.
Så det kører PDF LaTeX, det kopierer det til den mappe jeg vil have det skal kopieres til,
det cd'er til mappen og gør andre ting,
men alt det gør, er at anerkende Når en fil ændringer,
og hvis det ændrer, så vil det køre de kommandoer, det er meningen at løbe
når filen ændres. >> [Studerende] Okay.
Jeg ved ikke, hvor de globale gøre filer er for mig at tjekke det ud.
Andre spørgsmål? Alt fra fortiden quizzer? Eventuelle pointer ting?
Der er subtile ting med pegepinde som -
Jeg har ikke tænkt mig at være i stand til at finde en quiz spørgsmål på det -
men ligesom denne slags ting.
Sørg for at du forstår, at når jeg siger int * x * y -
Det er ikke ligefrem noget her, tror jeg.
Men ligesom * x * y, de er 2 variabler, der er på stakken.
Når jeg siger x = malloc (sizeof (int)), x er stadig en variabel på stakken,
malloc er nogle blok over i den bunke, og vi har x pege på den bunke.
>> Så noget på stakken peger på bunke.
Når du malloc noget, du uundgåeligt gemme det inde i en pegepind.
Så det pointer er på stakken, den malloced blok er på heapen.
En masse mennesker bliver forvirrede og siger int * x = malloc, x er på heapen.
Nej Hvad x peger på, er på heapen.
x selv er på stakken, medmindre uanset af hvilken grund, du har x være en global variabel,
i hvilket tilfælde det sker for at være i et andet område af hukommelsen.
Så at holde styr, er disse box og pil diagrammer temmelig almindeligt for quizzen.
Eller hvis det ikke er på quiz 0, vil det være på quiz 1.
Du skal vide alle disse, trinene i kompilering
siden du var nødt til at svare på spørgsmål om dem. Ja.
[Studerende] Kunne vi gå over disse skridt - >> Sure.
Før trin og udarbejdelse vi har forbehandling,
kompilering, montage, og sammenkædning.
Forbehandling. Hvad betyder det så?
Det er den nemmeste skridt i - ja, ikke som -
det betyder ikke, det bør være indlysende, men det er den nemmeste skridt.
I gutter kunne gennemføre det selv. Yeah.
[Studerende] Tag hvad du har i din omfatter som denne, og det kopierer og derefter definerer også.
Det ser for ting som # include og # define,
og det bare kopier og pastaer, hvad de rent faktisk betyder.
Så når du siger # include cs50.h er præprocessoren kopiere og indsætte cs50.h
i denne linje.
Når du siger # define x at være 4, præprocessoren går igennem hele programmet
og erstatter alle forekomster af x med 4.
Så præprocessoren tager en gyldig C-fil og udsender en gyldig C-fil
hvor tingene er blevet kopieret og indsat.
Så nu kompilering. Hvad betyder det så?
[Studerende] Det går fra C til binær.
>> [Bowden] Det går ikke hele vejen til binær.
[Studerende] Til maskinkode så? >> Det er ikke maskine kode.
[Studerende] Assembly? >> Forsamling.
Det går til forsamlingen, før den går hele vejen til C-kode,
og de fleste sprog gøre noget som dette.
Pick enhver højniveausprog, og hvis du kommer til at kompilere det,
det er sandsynligt, at kompilere i trin.
Først det kommer til at kompilere Python til C, så det kommer til at kompilere C til Assembly,
og derefter forsamlingen vil blive oversat til binær.
Så kompilering vil bringe det fra C til forsamling.
Ordet samle betyder normalt at bringe det fra et højere niveau
til et lavere niveau programmeringssprog.
Så dette er den eneste trin i udarbejdelse, hvor du starter med et højniveausprog
og ender i en lav-niveau sprog, og det er grunden til, at trin kaldes kompilering.
[Studerende] Under kompilering, lad os sige, at du har gjort # include cs50.h.
Vil compiler rekompilere det cs50.h, ligesom de funktioner, der er derinde,
og omsætte det til Assembly kode så godt,
eller vil den kopiere og indsætte noget, der har været præ-forsamlingen?
cs50.h vil stort set aldrig ender i forsamlingen.
Ting som funktion prototyper og ting er bare for dig at være forsigtig.
Det garanterer, at compileren kan kontrollere ting som du ringer funktioner
med de rigtige tilbagevenden typer og de rigtige argumenter og kram.
>> Så cs50.h vil blive forbehandles i filen, og derefter når det er kompilering
Det er dybest set smidt væk efter det gør sikker på, at alt bliver kaldt korrekt.
Men de funktioner der er defineret i CS50 biblioteket, som er adskilt fra cs50.h,
de vil ikke blive særskilt udarbejdet.
Det vil faktisk komme ned i sammenkædningen trin, så vi vil komme til at i et sekund.
Men først, hvad samling?
[Studerende] forsamlingen til binær? >> Yeah.
Samling.
Vi kalder det ikke kompilere fordi forsamlingen er temmelig meget en ren oversættelse af binær.
Der er meget lidt logik i at gå fra forsamlingen til binær.
Det er ligesom at slå op i en tabel, åh, har vi denne instruktion;
der svarer til binært 01110.
Og så de filer, samle generelt udgange er. O-filer.
Og. O-filer er, hvad vi sagde før,
hvordan en fil ikke behøver at have en hovedfunktion.
Enhver fil kan opgøres ned til en. O fil, så længe det er en gyldig C-fil.
Det kan udarbejdes ned. O..
Nu forbinder er hvad der rent faktisk bringer en masse. O-filer og bringer dem til en eksekverbar.
Og så hvad linking gør, er du kan tænke på det CS50 biblioteket som en. O-fil.
Det er en allerede kompileret binær fil.
Og så når du kompilere din fil, din hello.c, som opfordrer GetString,
hello.c bliver kompileret ned til hello.o,
hello.o er nu i binær.
Det bruger GetString, så det skal gå over til cs50.o,
og linkeren smooshes dem sammen og kopierer GetString ind i denne fil
og kommer ud med en eksekverbar fil, der har alle funktioner, den har brug for.
Så cs50.o er faktisk ikke en O-fil, men det er tæt nok, at der ikke er nogen fundamental forskel.
Så forbinder bare bringer en masse filer sammen
der hver for sig indeholder alle de funktioner, jeg skal bruge
og skaber den eksekverbare, der rent faktisk kører.
>> Og så det er også, hvad vi sagde før
hvor du kan have 1000. c-filer, du samle dem alle til. o-filer,
som formentlig vil tage et stykke tid, så du ændre 1. c. fil.
Du behøver kun at kompilere at 1. C. fil og derefter sammenkæde alt andet,
linke det hele sammen igen.
[Studerende] Når vi forbinder vi skriver lcs50?
Ja, så-lcs50. Det flag signaler til linkeren at du bør forbinder i biblioteket.
Spørgsmål?
Har vi gået over binær andet end at 5 sekunder i den første forelæsning?
Det tror jeg ikke.
Du skal kende alle de store Os at vi har været igennem,
og du bør være i stand til, hvis vi gav dig en funktion,
du bør være i stand til at sige, det er big O, groft. Eller godt, big O er ru.
Så hvis du ser indlejret for-løkker looping over det samme antal ting,
ligesom int i, i <n; int j, j > [studerende] n potens. >> Det plejer at være n potens.
Hvis du tredobbelt har indlejret, det har en tendens til at være n kubik.
Så den slags ting, du bør være i stand til at påpege det samme.
Du skal vide indsættelse sortere og boble sortere og flette sortere og alle dem.
Det er nemmere at forstå, hvorfor det er dem n kvadreret og n log n og alt dette
fordi jeg tror, ​​der var på en quiz et år, hvis vi dybest set gav dig
en implementering af boble sortere og sagde: "Hvad er køretiden for denne funktion?"
Så hvis du genkende det som boble sortere, så du straks kan sige n potens.
Men hvis du bare ser på det, behøver du ikke engang nødt til at indse det er boble sort;
du kan bare sige dette gør det og det. Dette er n potens.
[Studerende] Er der nogle hårde eksempler du kan komme op med,
ligesom en lignende idé at finde ud af?
>> Jeg tror ikke, vi ville give dig nogen hårde eksempler.
Boblen slags ting er omtrent lige så hård som vi ville gå,
og selv det, så længe du forstå, at du iteration over arrayet
for hvert element i arrayet, som er vil være noget, der er n potens.
Der er generelle spørgsmål, som lige her har vi - Oh.
Bare den anden dag, Doug hævdede, "Jeg har opfundet en algoritme, der kan sortere et array
"Af n tal i O (log n) tid!"
Så hvordan kan vi vide det er umuligt?
[Uhørlig student svar] >> Yeah.
I det mindste, skal du røre ved hvert element i array,
så det er umuligt at sortere et array af -
Hvis alt er i usorteret orden, så du vil komme til at røre alt i array,
så det er umuligt at gøre det i mindre end O n.
[Studerende] Du viste os, at eksempel på at være i stand til at gøre det i O n
hvis du bruger en masse hukommelse. >> Yeah.
Og that's - jeg har glemt hvad that's - Er det tælle slags?
Hmm. Det er et helt tal sortering algoritme.
Jeg var på udkig efter det særlige navn for dette, at jeg ikke kunne huske i sidste uge.
Yeah. Det er de typer af slags, der kan udrette ting i big O n.
Men der er begrænsninger, ligesom du kun kan bruge tal op til et vist antal.
Plus, hvis du forsøger at sortere noget that's -
Hvis dit array er 012, -12, 151, 4 mio
så er enkelt element vil helt ødelægge hele sortering.
>> Spørgsmål?
[Studerende] Hvis du har en rekursiv funktion, og det bare gør det rekursive kald
inden for en tilbagevenden erklæring, er det halerekursive,
og så ville det ikke bruge mere hukommelse under runtime
eller det ville i det mindste bruge sammenlignelige hukommelse som en iterativ løsning?
[Bowden] Ja.
Det ville sandsynligvis være noget langsommere, men ikke rigtig.
Halerekursive er temmelig godt.
Ser igen på stakrammer, lad os sige, at vi har main
og vi har int bar (int x) eller noget.
Dette er ikke en perfekt rekursiv funktion, men tilbagevenden bar (x - 1).
Så selvfølgelig, det er forkert. Du har brug for base-sager og kram.
Men ideen her er, at dette er halerekursive,
hvilket betyder, når main opkald bar det kommer til at få sin stack ramme.
I denne stakramme der kommer til at være lidt blok af hukommelse
der svarer til dens argument x.
Og så lad os sige main sker for at kalde bar (100);
Så x kommer til at starte ud som 100.
Hvis compileren erkender, at dette er en hale rekursiv funktion,
så når bar gør sin rekursivt kald til bar,
i stedet for at lave en ny stak ramme, som er der, hvor stakken begynder at gro i vid udstrækning,
sidste ende vil det løbe ind i bunke og derefter får du segfault'er
fordi hukommelsen begynder at kollidere.
>> Så i stedet for at gøre sit eget stakramme, kan det indser,
hey, jeg aldrig rigtig har brug for at vende tilbage til dette stakramme,
så i stedet vil jeg bare udskifte dette argument med 99 og derefter starte bar hele.
Og så vil det gøre det igen, og det vil nå tilbage bar (x - 1),
og i stedet for at lave en ny stakramme, vil det bare erstatte det aktuelle argument med 98
og derefter hoppe tilbage til begyndelsen af ​​bar.
Disse operationer, der erstatter denne 1 værdi på stakken og hoppe tilbage til begyndelsen,
er temmelig effektiv.
Så ikke alene er det den samme hukommelse skik som en særskilt funktion, som iterativ
fordi du kun bruger 1 stakramme, men du er ikke lider ulemper
for at skulle kalde funktioner.
Opkaldsfunktioner kan være lidt dyrt, fordi det har at gøre alt dette setup
og nedtagning og alle disse ting.
Så denne hale rekursion er god.
[Studerende] Hvorfor er det ikke skaber nye skridt?
Fordi det indser det ikke behøver at.
Opfordringen til bar er bare returnere den rekursivt kald.
Så det behøver ikke at gøre noget med den returnerede værdi.
Det er bare at gå til straks returnere den.
Så det er bare at erstatte sin egen argumentation og starte forfra.
Og også, hvis du ikke har halen rekursive version,
så får du alle disse barer, hvor når denne bar returnerer
det har at returnere sin værdi til denne ene, så det bar straks returnerer
og det returnerer dens værdi til denne ene, så er det bare at gå til straks at returnere
og vende tilbage sin værdi til denne ene.
Så du gemme denne popping alle disse ting ud af stakken
da returværdien bare vil blive passeret hele vejen tilbage op alligevel.
Så hvorfor ikke bare erstatte vores argument med den opdaterede indlæg og starte forfra?
Hvis funktionen ikke er halerekursive, hvis du gør noget lignende -
[Studerende], hvis bar (x + 1). >> Yeah.
>> Så hvis du sætter den i stand, så du laver noget med returværdien.
Eller selv hvis du bare ikke vender tilbage 2 * bar (x - 1).
Så nu bar (x - 1) behov for at vende tilbage for at det at beregne 2 gange denne værdi,
så nu er det behøver sin egen separate stakramme,
og nu, uanset hvor hårdt du prøver, du vil få brug for -
Dette er ikke halerekursive.
[Studerende] Vil jeg forsøge at bringe en rekursion at sigte mod en hale rekursion -
[Bowden] I en ideel verden, men i CS50 du ikke behøver at.
For at få hale rekursion, generelt, skal du oprette et ekstra argument
hvor bar vil tage int x i y
og y svarer til den ultimative ting, du ønsker at vende tilbage.
Så da dette du vil vende tilbage bar (x - 1), 2 * y.
Så det er bare et højt niveau, hvordan du transformerer ting at være halerekursive.
Men den ekstra argument -
Og så i sidste ende, når du har nået dit base case, skal du bare returnere y
fordi du har været akkumulere hele tiden returværdien, du ønsker.
Du slags har gjort det iterativt men ved hjælp af rekursive kald.
Spørgsmål?
[Studerende] Måske omkring pointer aritmetik, ligesom når du bruger strenge. >> Sure.
Pointer aritmetik.
Når du bruger strenge er det nemt, fordi strengene er char stjerner,
chars er evigt og altid en enkelt byte,
og så pointer aritmetik svarer til regelmæssig aritmetiske når du beskæftiger sig med strygere.
Lad os bare sige char * s = "hej".
Så vi har en blok i hukommelsen.
Det kræver 6 bytes, fordi du altid har brug for null terminator.
Og char * s vil pege på begyndelsen af ​​dette array.
Så s peger der.
Nu, dette er dybest set, hvordan enhver matrix virker,
uanset om det var et afkast ved at allokere eller om det er på stakken.
Enhver matrix er grundlæggende en pointer til starten af ​​arrayet,
og derefter en array-operation, enhver indeksering, er bare at gå ind i den pågældende matrix en vis forskydning.
>> Så når jeg siger noget i retning af s [3], og dette kommer til at s og tælle 3 tegn i.
So s [3], har vi 0, 1, 2, 3, således s [3] vil henvise til denne l..
[Studerende] Og vi kunne nå den samme værdi ved at gøre s + 3 og derefter parenteser stjerne?
Ja.
Dette svarer til * (s + 3);
og det er evigt og altid ækvivalent uanset hvad du gør.
Du behøver aldrig at bruge konsollen syntaks.
Du kan altid bruge * (s + 3) syntaks.
Folk har en tendens til at kunne lide konsollen syntaks, selv om.
[Studerende] Så alle arrays er faktisk bare pointere.
Der er en lille forskel, når jeg siger int x [4]; >> [studerende] Betyder det skabe hukommelsen?
[Bowden] Det vil skabe 4 int'er på stakken, så 16 bytes samlet.
Det kommer til at skabe 16 bytes på stakken.
x er ikke gemt nogen steder.
Det er blot et symbol for starten af ​​ting.
Fordi du erklærede vifte indersiden af ​​denne funktion,
hvad compileren vil gøre er bare at erstatte alle forekomster af variablen x
med, hvor det skete at vælge at sætte disse 16 bytes.
Det kan ikke gøre det med char * s, fordi s er et virkeligt pointer.
Det er gratis at så pege på andre ting.
x er en konstant. Du kan ikke få det punkt til et andet array. >> [Studerende] Okay.
Men denne idé, denne indeksering, er den samme, uanset om det er en traditionel opstilling
eller hvis det er en pointer til noget, eller hvis det er en pointer til en malloced array.
Og i virkeligheden er det så svarer, at det er også det samme.
Det faktisk bare oversætter Hvad er der indeni af konsollerne, og hvad der er tilbage af konsollerne,
lægger dem sammen, og dereferences.
Så dette er lige så gyldig som * (s + 3) eller s [3].
[Studerende] Kan du have pointers peger på 2-dimensionelle arrays?
>> Det er sværere. Traditionelt, no.
En to-dimensionelle række er blot en 1-dimensionalt array med nogle praktisk syntaks
fordi når jeg siger int x [3] [3], det er virkelig bare 1 array med 9 værdier.
Og så når jeg indeks, compileren ved, hvad jeg mener.
Hvis jeg siger x [1] [2], den kender jeg ønsker at gå til den anden række, så det kommer til at springe de første 3,
og så det ønsker den anden ting i det, så det kommer til at få denne ene.
Men det er stadig bare en enkelt-dimensionel array.
Og så hvis jeg ønskede at tildele en pegepind til denne opstilling,
Jeg vil sige int * p = x;
Den type af x er bare -
Det er groft at sige type x da det er bare et symbol, og det er ikke en egentlig variabel,
men det er bare en int *.
x er blot en pointer til starten af ​​dette. >> [Studerende] Okay.
Og så vil jeg ikke være i stand til at få adgang til [1] [2].
Jeg tror, ​​der er speciel syntaks for at erklære en pointer,
noget latterligt lignende int (* p [-. noget helt latterlig jeg ikke engang kender.
Men der er en syntaks for at erklære pegepinde som med parenteser og ting.
Det kan ikke engang lade dig gøre det.
Jeg kunne se tilbage på noget, der ville fortælle mig sandheden.
Jeg vil lede efter den senere, hvis der er en syntaks for punkt. Men du vil aldrig se det.
Og selv syntaksen er så arkaisk, at hvis du bruger det, vil folk blive forvirret.
Multidimensional arrays er temmelig sjældne, som det er.
Du temmelig meget -
Tja, hvis du laver matrix ting, det kommer ikke til at være sjældne,
men i C du sjældent skal bruge flerdimensionale arrays.
Yeah. >> [Studerende] Lad os sige du har en virkelig lang array.
>> Så i virtuel hukommelse ser det ud til at være alle på hinanden følgende,
ligesom de elementer, lige ud for hinanden,
men i fysisk hukommelse, ville det være muligt for denne at blive opdelt? >> Ja.
Hvor virtuel hukommelse værker er det bare adskiller -
Enheden for tildelingen er en side, som har tendens til at være 4 kilobyte,
og så når en proces siger, hey, jeg vil bruge denne hukommelse,
operativsystemet vil tildele det 4 kilobyte for den lille blok af hukommelse.
Selv hvis du kun bruge en enkelt lille byte i hele blokken af ​​hukommelse,
operativsystemet vil give det fulde 4 kilobyte.
Så hvad dette betyder, jeg kunne have - lad os sige dette er min stack.
Denne stabel kunne adskilles. Min stak kan være megabyte og megabytes.
Min stack kan være enorme.
Men stakken selv skal opdeles i enkelte sider,
som hvis vi ser på herovre lad os sige dette er vores RAM,
hvis jeg har 2 GB RAM, det er faktisk adresse 0 ligesom den nulte byte af min RAM,
og dette er 2 gigabyte hele vejen herned.
Så denne side kan svare til denne blok herovre.
Denne side kan svare til denne blok herovre.
Denne ene kunne svare til denne ene herovre.
Så styresystemet er gratis at tildele fysisk hukommelse
til de enkelte side vilkårligt.
Og det betyder, at hvis denne grænse sker for at skræve et array,
et array sker for at være tilbage af dette og til højre for denne ordre på en side,
derefter at arrayet vil blive delt i fysisk hukommelse.
Og så når du afslutter programmet, når processen slutter,
Disse tilknytninger bliver slettet, og så er det gratis at bruge disse små blokke til andre ting.
Flere spørgsmål?
[Studerende] Markøren aritmetik. >> Oh yeah.
Strings var lettere, men ser på noget som int'er,
så tilbage til int x [4];
Hvorvidt dette er en matrix eller om det er en pointer til en malloced vifte af 4 heltal,
det kommer til at blive behandlet på samme måde.
[Studerende] Så arrays er på bunke?
[Bowden] Arrays er ikke på den bunke. >> [Studerende] Oh.
>> [Bowden] Denne type matrix tendens til at være på stakken
medmindre du erklærede det på - at ignorere globale variable. Brug ikke globale variabler.
Inde i en funktion jeg siger int x [4];
Det kommer til at skabe en 4-heltal blok på stakken for dette array.
Men denne malloc (4 * sizeof (int)), kommer til at gå på heapen.
Men efter dette punkt kan jeg bruge x og p i stort set den samme måde,
bortset fra de undtagelser, jeg sagde før om du kan tildele p.
Teknisk set deres størrelser er lidt anderledes, men det er helt irrelevant.
Du faktisk aldrig bruge deres størrelser.
Det p jeg kunne sige p [3] = 2; eller x [3] = 2;
Du kan bruge dem i nøjagtig de samme måder.
Så pointer aritmetik nu - Ja.
[Studerende] Har du ikke behøver at gøre p *, hvis du har konsollerne?
Konsollerne er en implicit dereference. >> Okay.
Faktisk også det du siger med det kan du få multidimensionale arrays
med pointere, er, hvad du kan gøre noget lignende, lad os sige, int ** pp = malloc (sizeof (int *) * 5);
Jeg vil bare skrive det hele ud først.
Jeg ville ikke have, at én.
Okay.
Hvad jeg gjorde her er - Det bør være pp [i].
Så pp er en pegepind til en pegepind.
Du mallocing pp til at pege på en række af 5 int stjerner.
Så i hukommelsen, du har på stakken pp.
Det kommer til at pege på en række af 5 blokke, der alle selv pointers.
Og da jeg så malloc hernede, jeg malloc at hver af disse individuelle pointers
skal pege på en separat blok på 4 byte på den bunke.
Så dette peger på 4 byte.
Og denne ene point til en anden 4 byte.
>> Og alle dem peger på deres egne 4 byte.
Dette giver mig en måde at gøre flerdimensionale ting.
Jeg kunne sige pp [3] [4], men nu er det ikke det samme som multidimensionelle arrays
fordi multidimensionelle arrays det oversat [3] [4] til en enkelt forskydning i x array.
Dette dereferences p, tilgår den tredje indeks, så dereferences at
og adgange - 4 ville være ugyldig - den anden indeks.
Betragtninger, da vi havde int x [3] [4] før som en flerdimensional matrix
og når du dobbeltklikker beslag det er virkelig kun en enkelt dereference,
du efter en enkelt pointer og derefter en forskydning,
dette er virkelig 2D referencer.
Du følger 2 separate pointers.
Så dette også teknisk tillader dig at have flerdimensionelle arrays
hvor hver enkelt array er forskellige størrelser.
Så jeg tror takkede multidimensionale arrays er, hvad det hedder
da virkelig den første ting kunne pege på noget, der har 10 elementer,
den anden ting kunne pege på noget, der har 100 elementer.
[Studerende] Er der nogen grænse for antallet af henvisninger, du kan have
peger på andre pointers? >> Nej.
De kan have int ***** p.
Tilbage til pointer aritmetik - >> [studerende] Oh. >> Yeah.
[Studerende] Hvis jeg har int *** p og så vil jeg gøre en dereference og jeg siger p * er lig med denne værdi,
er det kun kommer til at gøre 1 niveau dereferere? >> Ja.
Så hvis jeg vil have adgang til ting, at den sidste pointer peger på -
Så du gør *** p. >> Okay.
Så dette er p point til 1 blok, peger på en anden blok, peger på en anden blok.
Så hvis du gør * p = noget andet, så du ændrer dette
nu peger på en anden blok. >> Okay.
>> [Bowden] Og hvis disse blev malloced, så har du nu lækket hukommelse
medmindre du tilfældigvis har forskellige referencer af disse
da du ikke kan komme tilbage til dem, dem, du lige smed.
Pointer aritmetik.
int x [4] kommer til at tildele en vifte af 4 heltal
hvor x vil pege på begyndelsen af ​​grupperingen.
Så når jeg siger noget i retning af x [1], jeg vil have det til at betyde at gå til den anden heltal i array,
hvilket ville være denne.
Men virkelig, det er 4 bytes i arrayet da denne heltal optager 4 byte.
Så en forskydning på 1 virkelig betyder en forskydning på 1
gange større uanset typen af ​​arrayet er.
Dette er en vifte af heltal, så den ved at gøre 1 gange størrelsen af ​​int, når den ønsker at udligne.
Den anden syntaks. Husk, at dette svarer til * (x + 1);
Når jeg siger pointer + 1, hvad de hjemvendte er den adresse, markøren er lagring
plus 1 gange størrelsen af ​​typen af ​​markøren.
Så hvis x = ox100, så x + 1 = ox104.
Og du kan misbruge dette og sige noget i retning af char * c = (char *) x;
og nu c vil være den samme adresse som x.
c vil være lig med ox100,
men c + 1 vil være lig med ox101
da pointer aritmetik afhænger af typen af ​​markøren, du tilføjer til.
Så c + 1, det ser på c, det er en char pointer, så det kommer til at tilføje 1 gange størrelsen af ​​char,
der vil altid være 1, så du får 101,
hvorimod hvis jeg gør x, hvilket er også stadig 100, x + 1 vil være 104.
[Studerende] Kan du bruge c + + for at fremme din pointer med 1?
Ja, du kan.
Du kan ikke gøre det med x, da x er bare et symbol, det er en konstant, og du kan ikke ændre x.
>> Men c sker der bare være en pegepind, så c + + er helt i orden, og det vil forøges med 1.
Hvis c var bare en int *, så c + + ville blive 104.
+ + Gør pointer aritmetik, ligesom c + 1 ville have gjort pointer aritmetik.
Dette er faktisk, hvordan en masse ting som sammenfletning sort -
I stedet for at skabe kopier af ting, kan du i stedet passere -
Ligesom hvis jeg ønskede at videregive denne halvdel af rækken - lad os slette noget af dette.
Lad os sige, at jeg ønskede at passere denne side af array i en funktion.
Hvad ville jeg gå til denne funktion?
Hvis jeg passerer x, jeg passerer denne adresse.
Men jeg ønsker at videregive denne bestemt adresse. Så hvad skal jeg gå?
[Studerende] Pointer + 2?
[Bowden] Så x + 2. Ja.
Det kommer til at være denne adresse.
Du vil også meget ofte se det som x [2] og derefter adressen på det.
Så du er nødt til at tage adressen af ​​det, fordi beslaget er en implicit dereference.
x [2] refererer til den værdi, der er i denne boks, og du derefter vil adressen på den kasse,
så du siger & x [2].
Så det er sådan noget i fletningen slags, hvor du vil passere halv listen til noget
du virkelig bare passere & x [2], og nu så langt som den rekursive kald angår,
min nye opstilling starter der.
Last minute spørgsmål.
[Studerende] Hvis vi ikke sætter et og-tegn eller en - hvad er det hedder? >> Star?
[Studerende] Star. >> Teknisk dereference operatør, men - >> [studerende] Dereference.
>> Hvis vi ikke sætte en stjerne eller et og-tegn, hvad sker der, hvis jeg bare sige y = x og x er en pointer?
Hvad er den type af y? >> [Studerende] Jeg vil bare sige, det er pointer 2.
Så hvis du bare sige y = x, nu x og y peger på den samme ting. >> [Studerende] Peg på det samme.
Og hvis x er en int pointer? >> Det ville klage, fordi du ikke kan tildele pointers.
[Elev] Okay.
Husk at pointere, selvom vi trækker dem som pile,
virkelig alle de store - int * x - virkelig alle x er lagring er noget i ox100,
som vi tilfældigvis repræsentere som peger på blok lagret ved 100.
Så når jeg siger int * y = x; jeg bare kopiere ox100 i y,
som vi bare kommer til at repræsentere som y, også peger på ox100.
Og hvis jeg siger int i = (int) x; så jeg kommer til at lagre uanset værdien af ​​ox100 er
indersiden af ​​det, men nu er det kommer til at blive fortolket som et heltal i stedet for en pegepind.
Men du har brug den støbte ellers vil klage.
[Studerende] Så mener du at kaste -
Er det kommer til at være udslagsgivende int for x eller støbning int af y?
[Bowden] Hvad?
[Elev] Okay. Efter disse parenteser er der vil være en x eller ay der?
>> [Bowden] Enten. x og y er ækvivalente. >> [Studerende] Okay.
Fordi de er begge pointers. >> Yeah.
[Studerende] Så det ville gemme den hexadecimale 100 i heltal form? >> [Bowden] Yeah.
Men ikke værdien af ​​hvad det peger på.
[Bowden] Yeah. >> [Studerende] Så bare adressen i heltal form. Okay.
[Bowden] Hvis du ønskede at for nogle bizarre grund,
kunne du udelukkende beskæftige sig med pegepinde og aldrig beskæftige sig med heltal
og bare være ligesom int * x = 0.
Så du kommer til at blive virkelig forvirret, når pointer aritmetik begynder at ske.
Så de tal, de gemmer er meningsløse.
Det er bare hvordan du ender fortolke dem.
Så jeg er fri til at kopiere ox100 fra en int * til en int,
og jeg er fri til at tildele - Du er sandsynligvis kommer til at få råbte på for ikke støbning -
Jeg er fri til at tildele noget lignende (int *) ox1234 ind i denne vilkårlige int *.
Så ox123 er lige så gyldig en hukommelse adresse, som er & y.
& Y sker for at returnere noget, der er temmelig meget ox123.
[Studerende] Ville det være en rigtig cool måde at gå fra hexadecimal til decimal form,
gerne, hvis du har en pegepind, og du kaster det som en int?
[Bowden] Du kan virkelig bare udskrive med lignende printf.
Lad os sige, at jeg har int y = 100.
Så printf (% d \ n - som du allerede burde vide - udskrive denne som et heltal,% x.
Vi vil bare udskrive det som hexadecimal.
Så en pointer ikke er gemt som hexadecimal,
og et helt tal ikke er gemt som decimal.
Alt er gemt som binær.
Det er bare at vi er tilbøjelige til at vise markører som hexadecimal
fordi vi tænker på ting i disse 4-byte blokke,
og hukommelsesadresser tendens til at være velkendt.
Vi er som, hvis den starter med bf, så tilfældigvis er på stakken.
Så det er bare vores fortolkning af henvisninger som hexadecimal.
Okay. Eventuelle sidste spørgsmål?
>> Jeg vil være her for en smule efter, hvis du har noget andet.
Og det er slutningen af ​​det.
>> [Studerende] Yay! [Bifald]
>> [CS50.TV]