[Powered by Google Translate] [Vecka 4, Fortsättning]
[David J. Malan - Harvard University]
[Detta är CS50. - CS50.TV]
>> Detta är CS50, och detta är slutet på vecka 4.
Så några goda nyheter och dåliga nyheter.
Ingen föreläsning på måndag, ställ inga problem nästa vecka. [Studenter hejar]
Du kommer inte att gilla om detta är på väg.
Men vi har det i stället nästa onsdag,
och det finns också per kursplanen 1 Fredag ​​föreläsning nästa fredag ​​så att vi kan hålla på rätt spår.
Men allt kommer att filmas som vanligt, så att inte oroa dig.
>> Och med avseende på frågesport 0 vad vi ska göra mot veckans slut
är post på kursens hemsida cs50.net en förklaring
om vilken typ av förväntningar bör du ha när det kommer till den första frågesporten.
I allmänhet kommer det att vara flervalsfrågor, sant-falskt, kort svar, korta kodning problem.
Du kommer inte att vänta att genomföra motsvarande
av ett problem som du skulle se på en pset, som du har en dator
och en debugger och liknande, men det kommer att bli små kodning problem.
>> Och faktiskt, den bästa guide för att få en känsla för vad CS50 frågesporter är som
är att gå till cs50.net, gå till frågesporter länken,
och du kan se de senaste åren värde av frågesporter.
Bara inse att läroplanen inte alltid varit densamma genom åren.
Ibland kan vi tillägga, ibland subtrahera,
så om du ser något ämne på ett av de gamla frågesporter
att du har ingen aning om vad det pratar om, det är antingen att vi täckte det
eller att vi inte täckte det.
Men i form av recensioner, denna söndag, måndag och tisdag
samt en kurs hela översyn session på söndag kväll -
tid och plats kommer att meddelas på kursens hemsida -
du har alla möjlighet att granska med kursens undervisning stipendiater
material för detta år, både i snitt och som en fullständig klass,
och de kommer att filmas som vanligt också.
>> Okej. Så utan vidare, en kommentar på godkänd / underkänd och add / drop.
Du kanske har sett mina anteckningar i går kväll, och det är egentligen bara en del ytterligare tillförsikt
att om du hör till dem speciellt mindre bekväm eller någonstans mittemellan
och du känner bara lite i över huvudet,
inser att det är faktiskt ganska vanligt, och det finns en riklig stödstruktur på plats,
varav kontorstid var inställda på att förbättras hela mer per min e kväll,
och inser också att ett alternativ som godkänt / underkänt för en klass som denna
verkligen är tänkt som en mekanism för att ta udden av en kurs som denna,
så igen om du tillbringar de 10, 15, 20 timmar
bara försöka få lite pset till jobbet och du vet att du är 90-95% av vägen dit
men du kan inte hitta några jävla bugg i en godkänd / underkänd modell som är typ av okej.
>> Tanken är att med denna mekanism du sedan kan gå fokusera på dina andra psets
eller sova eller vad det är som du vill fokusera på.
Så inser att du har till denna kommande tisdag - tekniskt den 5: e måndag,
men det är en helgdag, så detta kommer tisdag - att växla från godkänd / underkänd till graderade eller vice versa.
Och om du är riktigt på stupet och tänker släppa helt och hållet,
vänligen fånga mig efter föreläsning eller släpp mig ett meddelande.
Vi vill gärna minst chatt innan du bjuder adjö.
Okej. Så vi började ta stödhjul från förra gången.
Framför allt har vi fokuserat på snöre.
String är något som deklareras i CS50 biblioteket,
särskilt i den filen som heter cs50.h som vi börjar titta på denna och nästa vecka.
Men sträng är egentligen bara en förenkling av något
Det är lite mer arcanely beskrivs som char *.
Röding vi känner till. Det är bara ett enda tecken.
Men * per måndag betecknas vad? >> [Elev] En pekare.
En pekare. Och vad är en pekare? >> [Elev] En adress.
>> Det är som en adress, en plats i minnet.
Vad är en adress eller plats eller minne?
Återigen, vi alla har bärbara datorer med en spelning eller 2 gigabyte RAM-minne sannolikt dessa dagar,
och det betyder att du har en miljard eller 2 miljarder byte värde av minne.
Och det spelar ingen roll egentligen vad det fysiskt ser ut,
men ta på tro att du kan numrera alla de enskilda byte som din egen laptop har -
detta är byte 0, är ​​denna bitgrupp 1, är detta byte 2 miljarder -
och det är precis vad en dator gör.
När du allokera utrymme för en enda karaktär, till exempel,
Det har uppenbarligen att leva någonstans i datorns minne,
och kanske är det på byte nummer 12345,
och det är någonstans här uppe i datorns minne.
Och adressen då detta tecken är 12345.
>> Nu, i vecka 0 igenom nu hittills har vi inte riktigt brydde
var i minnet saker lagras eftersom vi brukar använda symboler,
variabler och arrayer att faktiskt få på våra uppgifter.
Men som med måndag och alla mer idag, du kommer nu att få
alla mer uttrycksfulla funktioner med att skriva program
att verkligen manipulera en dators minne men du tycker passar,
både bra ändamål och dåliga,
buggar är en mycket vanlig följd vid denna punkt att lära här.
Men vad betyder det egentligen att vara char *?
Låt oss gå vidare tillbaka till - och vi ska återkomma till Binky som utlovat idag.
Låt oss gå till ett enkelt exempel här.
Låt mig spara filen som compare.c, och låt mig bara få lite mall kod här
så inkluderar stdio.h, låt mig också ge mig själv omfattar cs50.h. Jag zooma in uppe.
Låt mig börja skriva huvudsakliga int, main (void), och nu vill jag göra något så här:
printf ("Ge mig en sträng:") och sedan kommer jag att använda strängen s får getString
för att få en sträng från användaren, då kommer jag att uppmana användaren att en annan.
("Ge mig en annan sträng:") och jag kommer att be dem via getString att få det.
Jag kallar det t eftersom t kommer efter s och s är ett fint namn för en sträng om det är ganska allmänna.
Så GetString, och nu vill jag bara göra en sanity check och jag kommer att säga
if (s == t) då jag ska bara tala om för användaren printf ("Du skrev samma sak \ n");
annars ska jag skriva ut något liknande ("du skrev något annat! \ n")
eller vad meningen kommer att bli. Så något liknande.
Sedan som vanligt, jag återkommer 0 som bara innebar att inget dåligt hänt,
och jag kommer att gå vidare och kompilera och köra programmet.
>> Men på måndag vi körde detta program,
och faktiskt fick veta att HELLO inte HEJ och adjö är inte adjö.
Det beteende som vi såg var lite mer om detta.
Låt mig gå in i min källa katalog, zooma in här, och låt oss gör jämföra.
Sammanställt okej. Låt mig köra jämföra. Ge mig en sträng: HELLO.
Ge mig en annan sträng: HELLO.
Du skrev något annat!
Nåväl, låt mig prova något enklare som 50, 50. Du skrev något annat!
Hej, hej. Så klart är något på gång här.
Men vad var förklaringen till varför?
Tydligen är linje 12 är helt dysfunktionella.
Vad är det grundläggande problemet här? Ja. >> [Elev] Det jämföra adresserna.
Ja, exakt. Det är faktiskt jämföra adresserna
där hej och HELLO lagras.
Det är inte att jämföra bokstäverna HELLO om och om igen,
eftersom vad som verkligen hände, hela tiden vi har använt GetString -
Denna tavlan är återigen vår dators minne,
och låt oss säga att jag kallar GetString efter att ha förklarat en variabel s.
Hur ser mitt minne ut?
Låt oss säga godtyckligt att s ser ut så här. Det är en kvadrat.
Och ganska mycket varje gång jag har ritat en bit av minnet på skärmen
om det är 32 bitar har jag rita rutor som detta eftersom verkligen i apparaten,
en pekare, en adress, är 32 bitar. Det är samma sak som en int.
Som kan variera beroende på datorsystem.
De av er som är vagt bekant med det faktum att din Mac eller PC är 64 bitar,
som betecknar faktiskt att din dator använder 64-bitars pekare,
64-bitars adresser och bland upsides av detta är dina datorer
kan ha mycket mer RAM än förr.
Lång historia kort, tillbaka i dag när datorer används endast 32 bitar
att representera adresser, det största antalet byte du kan representera
i så fall var det om du har 32 bitar?
Så 4 miljarder, höger, eftersom 2 till 32 är 4 miljarder.
Detta antal har återkommande i kursen.
>> Så om du bara har 32 bitar, det högsta antalet du kan räkna till ungefär 4 miljarder.
Men det var en grundläggande begränsning av datorer tills för några år sedan
för om du bara kan räknas som högt som 4 miljarder,
det spelar ingen roll om du köper 8 gigabyte RAM-minne eller till och med 5 gigabyte RAM;
Du kan inte räkna så högt, så det var meningslöst.
Du kan bara komma åt de första 3 eller 4 gigabyte datorns minne.
Det är ett mindre problem nu, och du kan köpa MacBook Pro och Dells
med 8 gigabyte RAM-minne eller ännu mer i dessa dagar.
Men om jag fördela helt enkelt i det här programmet en pekare, som kallas en pekare s
kan det se ut så här på skärmen eftersom vi faktiskt behöver dra tillbaka detta skikt.
Jag fortsätter att säga sträng, men från och med måndag, är sträng verkligen char *,
adressen av vissa tecken.
Så låt oss ta att utbildning hjulet från även om vi kommer att fortsätta att använda GetString för nu.
Så jag har förklarat s, och detta är en bit av minne, 32 bitar.
Vad är här i minnet som standard? >> [Ohörbart elev svar]
Vad är det? >> [Elev] Garbage. >> Garbage. Exakt.
Om du programmeraren inte sätta ett värde i en variabel, vem vet vad det är?
Ibland kan du ha tur och det är 0, är ​​vilken typ av en fin, ren standardvärde,
men som vi såg Måndag, ibland är det fullständigt nonsens,
några riktigt stora positivt eller negativt tal som kom från var?
Ja. >> [Elev] Funktionen innan. >> Ja.
>> Ofta den funktion som fick kallas innan eftersom kom ihåg,
som du kallar funktioner i minnet, tar de upp mer och mer utrymme nerifrån och upp,
och så snart som funktionen returnerar, blir det minne återanvändas
av nästa kille som får kallas, vem använder din samma skiva minne.
Och om du har lämnat skräp där, tidigare värden,
Vi kan förväxla s ha något värde när det verkligen att vi inte har lagt något där.
Så vår RAM på denna punkt ser ut så här.
Nu på höger sida av linjen 7 vi kallar GetString,
som vi har gjort nu i flera veckor, men vad getString egentligen gör?
GetString skriven av CS50 personal är lite intelligent
att så snart som användaren börjar skriva nycklar och träffar Enter,
GetString räknar ut hur många tangenttryckningar gjorde användaren träff,
hur många tecken behöver jag tilldela RAM för.
Och när detta RAM kommer ifrån, vem vet?
Det är någonstans i datorns 2 gigabyte eller whatnot minne.
Men låt oss anta att datorn hittade utrymme för ordet HEJ här.
Ordet jag skrev var H-E-L-L-O.
Och om vi drar detta som en följd av tecken, kan vi dra det så här.
Men jag behöver göra 1 extra sak. Vad hör i slutet av varje sträng i C?
Null karaktär, som vi skriver som \ 0.
Det är tekniskt numret 0, men det omvända snedstrecket gör hela klarare
att detta är bokstavligen numret 0, heltalet 0;
Det är till exempel inte, citat-unquote 0 som du kan skriva på tangentbordet.
Så detta är HELLO.
>> Och vad har vi sagt på måndagen att en funktion som GetString
faktiskt tillbaka alla dessa veckor?
Det är inte returnera en sträng i sig eftersom det inte riktigt har betyder
eftersom strängarna finns inte. De är en slags tillverkning i CS50 biblioteket.
Vad är egentligen en sträng, mer tekniskt? >> [Elev] Det är det första tecknet.
Exakt. Det är helt enkelt adressen till det första tecknet som användaren skrivit in
Så om mitt ord HELLO slutar det upp på byte nummer 123 och sedan vid byte nummer 124,
125, 126 och så vidare, om jag bara nummer mina byte från 0 på upp,
vad som verkligen GetString återvänder är bokstavligen numret 123.
Så vad får placeras i s är antalet 123, inte bokstaven H inte ordet HELLO,
helt enkelt den adress där jag kan hitta den första bokstaven i HELLO.
Men det verkar inte som tillräckligt. Jag bad dig om en sträng, inte ett tecken.
Så hur vet vi eller den dator som ELLO typ av kommer tillsammans med H?
Vad är den typ av avtal som vi har? Ja.
[Eleven] Det håller berättar själv att hitta några fler tecken. >> Exakt.
>> Det är detta människa-dator konvention där när du arbetar med strängar,
annars känd nu som röding stjärnor, behöver du bara räkna ut
där i slutet av varje sträng i livet är att egentligen bara iteration över den med en for-slinga,
en while-slinga, vad som helst, så att när du hittar i slutet av strängen
nu kan du dra slutsatsen att åh, var hela ordet HELLO.
De av er med tidigare erfarenhet av programmering kanske känner i Java
Du kan bara ringa. längd och på andra språk kan du ringa längd eller liknande.
Det beror i många språk, särskilt saker som kallas objektorienterade språk,
längd något är typ av inkapslat inuti en bit data själv,
mycket som vi inkapslade ID och namn och hus inuti en student på måndagen.
Men C är mycket lägre nivå. Det finns inga objekt eller klasser, om du har hört dessa villkor innan.
Allt du har är verkligen minnesadresser.
Så detta är en slags gammaldags sätt att representera intressanta datastrukturer.
Du har ett startvärde som adressen för det första tecknet
och sedan bara någon godtycklig konvention som alla förbinder sig att följa.
Så hur är stränglängd genomförs, vi föreslår?
Strlen, strlen, som vissa av er har nu använt några gånger. Det är ganska enkelt, eller hur?
Det är som 2 rader kod.
Det är ganska mycket en for-slinga av något slag, kanske med ytterligare lokal variabel.
Men strlen har bara att ta en pekare och sedan börja leta efter \ 0.
>> Och så snart den finner det, kan det återgå totala antalet steg som det har tagit i den strängen.
Så vi kan dra slutsatsen detta vad som händer härnäst.
Anta då jag förklarar t som jag har gjort i linje 10.
Detta är något skräp värde. Vem vet först?
Men på den högra sidan av raden av 10 Jag ringer getString igen.
Vem vet var det hamnar?
Låt oss säga godtyckligt att operativsystemet fann utrymme för det vägen hit.
Jag råkar tillfällighet typ H-E-L-L-O igen,
och så att vi kan dra samma typ av bild.
Men det faktum att jag har ritas bilden är avsiktlig
eftersom det är en annan HÄLSNINGAR än denna.
Så här kan detta vara platsen 456, är detta 457, och så vidare.
Så vad får sätta där frågetecknet gång var?
I detta fall 456.
Vi plockar dessa siffror godtyckligt eftersom verkligen efter idag
Vi kommer inte att bry sig så mycket om vad adress någonting är.
Allt vi bryr oss om är att vi kan räkna ut adressen till någon bit data som HELLO.
>> Så egentligen vad de flesta människor gör i datavetenskap när man talar om minnesadresser
och prata om pekare specifikt,
snarare än att bry räkna ut 123 - vem bryr sig om det här faktiskt är,
Vi vet bara att det är någon numerisk adress -
Vi förenklar världen och bara säga att er pekar på det tecknet
och t pekar på det tecknet.
Och det faktum att det är en pil är ganska avsiktligt
eftersom bokstavligen nu s pekar på H och t pekar på den andra H
eftersom i slutet av dagen, spelar det ingen roll vad adressen är,
men det spelar roll att vi har förmågan att uttrycka den adressen med någon del av koden.
Vi har inte riktigt manipulerat dessa adresser bara ännu
så vi får se var vi kan invända och typ av göra saker med pekare,
men nu i linje 12 bokstavligen vilka värden vi jämför
Enligt denna berättelse i linje 12?
Vi säger är 123 lika lika med 456? Och det är definitivt inte fallet.
Och även begreppsmässigt, är denna pekare definitivt inte samma som det
eftersom du ringde getString två gånger och GetString försöker inte vara super smart,
det inte att försöka förverkliga, åh, skrev du HELLO 5 minuter sedan;
Låt mig ge dig samma pekaren som jag gav dig innan,
Det tilldelar bara en ny bit av minnet varje gång du kallar det.
>> Så hur fixar vi det här problemet?
Om högre nivå jag vill jämföra strängar hej och HELLO -
Jag bryr mig inte om tips - hur gör jag besvara frågan,
gjorde användaren skriva samma sak? Vad är nödvändigt här? Ja.
[Elev] Använd en funktion. >> Jag kan använda en funktion ur lådan.
Jag kan använda en funktion som kallas strcmp, s-t-r-c-m-p,
bara den förkortade versionen att säga sträng jämföra.
Och om vi går in till exempel jämföra 2, som är bland dagens åhörarkopior,
Jag gör precis det.
Jag höll allt annat lika från linje 1 ner till 26 eller så,
och nu märker denna del har förändrats bara lite.
Låt oss bortse linje 28 för en stund och bara fokusera på detta.
Vad gjorde vi säga måndag att str jämförelsen gör?
Den hanterar processen att ta 2 pekare, S och T i detta fall,
typ av praktiskt taget sätta fingret på dessa 2 bokstäver,
och vad det måste göra är något som en while-slinga eller en for-slinga,
och det står är dessa samma? Om så är fallet, förflyttar den fingrarna eller pekare framåt.
Är dessa samma, dessa samma, dessa samma,
dessa samma, dessa samma? Och ooh, jag i slutet av strängen både s och t.
Jag har inte hittat några motsägelser. Ja, dessa strängar är desamma.
Och vad jämför str avkastning om 2 strängar är lika, tydligen? Noll.
Så 0 är bra i det här fallet eftersom om det återvänder -1 eller +1,
det betyder att s bara råkar komma före t alfabetiskt eller efter t.
Och varför skulle det vara bra att ha en funktion som talar om vilken sträng kommer före
eller efter i ett lexikon?
[Elev] Söker. >> Sökning och sortering.
>> Så du kan göra saker som binär sökning eller bubbla sortera eller slå samman Sortera
där du måste jämföra saker.
Hittills vi har typ av klippa några hörn och bara talade om sortering
i samband med siffrorna eftersom det är trevligt och lätt att prata om,
men du kan säkert jämföra strängar, äpple och banan,
eftersom om äpple är känt att komma före banan, på liknande sätt,
kan du flytta strängar runt i minnet precis som Rob gjorde med merge Sortera i videon
och vi gjorde här på scenen med val Sortera, införande sortera och bubbla sortera.
Så var annars kan vi ta detta? Låt oss försöka det.
Låt oss slags glömma att lektionen för ett ögonblick och försök nu och kopiera 1.c att göra följande.
I linje 21 Jag säger ut något,
då jag får en sträng från användaren,
då jag kontrollera detta.
Vi har inte riktigt kommit in i denna vana än, men låt oss nu göra detta.
Låt oss faktiskt skal tillbaka detta skikt. Detta är verkligen char *. Den här killen är verkligen char *.
Så vad betyder det att kontrollera om s == NULL?
Det visar sig att när du ringer en funktion som GetString
eller mer generellt bara be en dator för att ge dig lite minne,
något kan gå fel.
Du kan vara galen och be datorn för en terabyte minne
genom att be om biljoner byte minne som bara inte finns i datorn,
men getString och andra funktioner behöver något sätt skriker på dig
om du har bett om för mycket.
Och hur GetString gör detta är om du har bett om mer minne
än vad som finns i datorn, även om det är super, super låg sannolikhet
eftersom ingen av oss kommer att skriva en biljon tecken och sedan trycka Enter,
men låg sannolikhet men det kan vara, vill jag ändå att kontrollera det i fall,
och den speciella värde som getString, svar, och andra funktioner avkastning
om något har gått fel är NULL i alla mössor.
>> Och vad är NULL? NULL råkar vara så att representera en pekare. Det är minnesadress 0.
Världen beslutade att godtyckligt, om detta är min dator minne - vet du vad? -
vi kommer att stjäla bara 1 byte i varje dators minne, och detta är platsen 0.
Vi kommer att ge den ett smeknamn av NULL, och vi kommer att lova
att vi aldrig kommer faktiskt sätta verklig data finns
eftersom vi bara godtyckligt behöver ett speciellt värde, 0, alias NULL,
så att vi kan skrika åt användare om något går fel.
Annars kan du kanske inte vet betyder 0 betyder sätta något här
eller betyder det något gick fel?
Vi måste alla vara överens om att NULL betyder ingenting tillbaka,
ingen faktisk adress returnerades.
Nu, här jag bara anta min mänskliga konvention av jag återvänder 1 från huvud
om något går fel.
Det beror huvud återkomst konvention är att återvända 0 om bra,
1 eller något annat värde om dåliga.
Men GetString och alla funktioner som erbjudanden i minnet returnerar null om något går dåligt.
>> Okej. Så tyvärr, misslyckas linje 27, super enkelt men det är helt för att kopiera strängen.
Varför? Vi kan se detta på följande sätt.
Jag hävdar i linje 27 att göra en kopia av s och kalla det inte.
Så jag inte ber användaren 2 strängar den här gången, jag säger bara värdet i s
bör läggas it också.
Så nu bara för att visa hur trasiga detta är, i linje 29 och framåt vad gör jag?
Först jag kontrollera om längden på t är större än 0.
Det finns vissa sträng där. Användaren skrivit något i.
Vad är linje 32 gör, tydligen?
[Ohörbart elev svar] >> Höger. Du kan typ av sluta det från vad jag sa att det gör.
Men tekniskt är vad detta gör? t [0] representerar vad?
[Studerande] Den nollte karaktär. >> [Malan] Den 0:e karaktär.
Eller mer människoliknande, det första tecknet i t, vad det är, H kanske i detta fall.
Och toupper gör vad den säger. Det kapitaliserar den nollte karaktär t och det förändrar det.
Så detta betyder ta 0:e karaktären av t, gör det versaler,
och lägger tillbaka den i samma läge.
Så om jag skriver hej med gemener, bör denna ändring den gemena h till ett kapital H.
Men problemet är att i ledningarna 35 och 36 vad jag ska göra är att skriva för oss s och t.
Och vad är din känsla?
Vad ska jag faktiskt att se om jag skrivit in hej i alla gemener?
Vad kommer att bli utskrivna? >> [Ohörbart elev svar] >> Vad är det?
[Eleven] Big H och resten små. >> Den stora H och resten små för vilka s eller t?
[Elev] Både. >> Båda. Exakt. Så låt oss se vad som händer här.
>> Låt mig gå vidare och sammanställa denna. Detta är Kopiering1, så Kopiering1. Okej.
Zooma in Låt mig gå vidare och köra Kopiering1, Enter, Säg något: hej små bokstäver.
Det kapitaliserade kopian, men det tydligen aktiverats originalet också,
eftersom det som händer nu i den här berättelsen?
I linje 27 jag faktiskt inte verkar kopiera strängen,
men även om du kanske har intuitivt hoppats att så är fallet,
om du tänker på den här bilden, vad som verkligen har jag gjort?
Hälften av bilden är densamma.
Så låt oss rulla tillbaka i tiden, så att t ännu inte finns i berättelsen.
S kan finnas i berättelsen, men låt oss små bokstäver hej den här gången.
Så låt mig fixa vad jag faktiskt skrivit i.
I det här fallet här har vi H-E-L-L-O.
Vi ska dra det som en följd av tecken, sätta min separator rader här och min \ 0.
Så det är där vi är när linje 1 till 24-ish, ge eller ta, har utförts.
Detta är bilden av mitt minne.
När jag kommer till rad 27, vad händer?
Precis som tidigare, får jag en pekare, som jag ska dra så detta torg.
Det kallas inte. Och vad är dess värde som standard? Vem vet? Vissa skräp värde.
>> Så jag ska abstrakt att bort som ett frågetecken.
Och så snart den högra sidan av linjen 27 utför, vad jag lägger in i t?
Samma sak som finns i talet.
Så om vi för ett ögonblick bort denna abstraktion av pilen och vi säger,
Åh, är detta minne belastning adress 123, när du säger t får s, semikolon,
du bokstavligen sätta 123 här.
Nu om vi sorts förenkla vår värld igen med bilder,
vad du egentligen gjort är bara läggas en annan pil i din värld
som är pekar från t till exakt samma sträng.
Så när i linje 31 och 32 jag faktiskt gå om att byta t [0],
vad är t [0] synes synonymt med nu? s [0]
Så det är allt som händer.
Och även om denna typ av känns lite låg nivå och svårbegripliga
och denna typ av känns kanske intuitivt här bör bara arbetat -
Jag har gjort kopior av saker innan och det bara fungerade -
om du verkligen tänker på vad en sträng egentligen är, det är en char *.
Nå, vad är det? Det är adressen till en viss karaktär.
Då kanske det är mer förnuftigt att när du försöker göra något
Super synes enkla som denna, är allt du gör kopierar en minnesadress.
Du faktiskt inte göra något med strängen själv.
Så även om du har ingen aning om hur man skulle lösa detta problem i kod,
hög nivå, konceptuellt, vad vi behöver göra för att göra ta bestyrkt kopia av s, tydligen?
Ja. >> [Elev] Ge det en ny plats? >> Exakt.
>> Vi måste ge t en helt ny plats.
Vi måste på något sätt skapa en värld där vi får en ny bit av minnet,
som bara för tydlighetens skull ska jag dra till höger nedanför detta, men det behöver inte vara där.
Men det måste vara av samma storlek, så jag ska rita dessa vertikala linjer på samma plats.
Det är bra om det är allt skräp från början. Vem vet vad som fanns där?
Men steg 1 kommer att behöva ge mig så mycket minne som jag behöver
för att passa en kopia av hej då räkna ut hur att kopiera h här, e här,
på l här och så vidare.
Men detta redan borde känna sig lite uppenbar, även om vissa detaljer är fortfarande abstrakt.
Om du vill kopiera den här strängen i detta, det är bara en for-slinga eller en while-slinga
eller något som du har blivit allt mer bekant.
Så låt oss prova det här. Låt mig gå in copy2.c.
I copy2.c vi har nästan samma program förutom linje 27.
Det ser lite komplicerat, men om vi bryter ner det bit för bit,
den vänstra sidan är densamma.
Char * t skapar denna sak i minnet, om än med ett frågetecken
eftersom vi har ingen aning om vad som finns där som standard.
På höger sida vi nu införa en ny funktion, malloc,
för minne fördela, ge mig minne,
och det tar tydligen hur många argument, hur många saker inuti parenteser?
Jag hörde knot 1 och 2, men det är bara 1.
Det finns ingen komma, vilket innebär att det är bara 1 sak innanför parentesen.
Även om det finns andra parenteser, låt mig belysa
vad som finns inuti de yttersta parenteser, och det är detta uttryck:
(Strlen (a) + 1) * sizeof (char).
Så om vi faktiskt tror att detta igenom, detta säger mig längden på talet.
Varför är jag dock lägga till 1 på längden? >> [Ohörbart elev svar]
Exakt. Vi behöver utrymme för den här killen på svansen, det sjätte tecknet som inte har någon engelska innebörd
men har speciella programmatiska innebörd.
>> Så vi behöver en + 1 för att eftersom strlen returnerar den mänskliga förväntningar av längd,
hej eller 5, ger det inte dig den extra null karaktär.
Så jag manuellt lägga detta med + 1.
Och sedan detta, (char) * storlek, har vi inte sett förut.
Detta är inte tekniskt en funktion.
Det är en speciell sökord som bara talar om vilken storlek är av någon datatyp på en dator
eftersom i verkligheten, några av oss har 32-bitars datorer.
Jag har en ganska gammal dator hemma, och det bara använder 32 bitar för att representera pekare.
Och så om jag storleken på en datatyp, kan det vara 32 bitar.
Men om jag använder min nya snygga dator, kan jag få tillbaka ett värde av 64 bitar
för ungefär en adress.
Så i detta fall, bara för att vara mycket säkra, vi kommer inte att hårt kod något liknande -
ja, vad är storleken på en röding enligt vad vi har sagt hittills?
Vi har ganska mycket sagt verbalt att det är 1 byte, och det är ganska mycket sant över hela linjen.
Men återigen, antaganden tenderar att vara dålig.
De leder till buggig programvara om folk använder din programvara på ett sätt du inte tänker.
Så låt oss abstrakta detta bort och bara mer allmänt säga
Jag behöver detta många bitar av minne
och varje bit av minne bör motsvara storleken av ett tecken,
som i själva verket är lika med 1 i detta fall, men det är ett mer allmänt sätt att skriva det.
Så om ordet är hej, hur många byte malloc fördela tydligen för Hello?
[Elev] Sex. >> Sex. Precis så många som vi har frågetecken på skärmen.
Och sedan ta en nu gissning baserat på din förståelse för GetString
vad återvänder malloc antagligen? >> [Elev] En adress.
En adress för vad? Första bit av minnet.
>> Vi har ingen aning om vad som finns där eftersom någon annan funktion
kunde ha använt detta minne tidigare.
Men malloc, liksom GetString, returnerar adressen för den första bitgruppen av minnet
att det har avsatts för dig.
Dock fylla vad den inte göra i denna tomt med ett omvänt snedstreck nolltecken
eftersom det visar sig att du kan använda malloc att allokera något: Ints, strängar, arrayer,
flottar, studerande strukturer.
Du kan använda malloc helt allmänt.
Den bryr sig inte eller måste veta vad du fördela minne för.
Så det vore förmätet att malloc att sätta en \ 0
I slutet av varje bit av minnet det ger dig
eftersom detta \ 0 sak är bara en konvention för stråkar.
Det är inte för Ints, det är inte för flottar, det är inte för studenter.
Och så gotcha med malloc är att bördan är helt på dig programmeraren
att komma ihåg hur många byte man tilldelats och inte någonsin använda en for-slinga
eller en while-slinga och gå förbi gränsen för bit av minne du har fått.
Annorlunda uttryckt så fort du allokera minne,
du kan inte be operativsystemet, åh, förresten, hur stor en bit av minne var detta?
Det är helt upp till dig att komma ihåg om du behöver det värdet.
>> Så låt oss se hur jag går att använda detta minne.
I linje 28 och 29 varför gör jag detta?
Bara total sanity check.
Bara om något gick fel, jag ber för någon galen mängd minne
eller jag har så många saker som körs på datorn att det bara inte tillräckligt med minne,
något liknande, jag åtminstone vill kontrollera null.
I verkligheten kommer de flesta datorer ger dig en illusion av att varje program
kan använda hela din RAM,
men ändå, om användaren skriver in någon galen lång sträng kanske eftersom de är en dålig kille
och de är faktiskt försöker att krascha ditt program eller hacka i det,
du vill åtminstone kontrollera returvärdet av malloc och om det är lika med noll.
Och om det gör det, låt oss bara sluta just nu eftersom jag inte vet vad jag ska göra i så fall.
Hur kopierar jag strängen? Det finns ett par sätt att göra detta.
Det finns str kopiera funktioner i C, men det är super enkelt för oss att göra detta gammaldags sätt.
>> Låt mig först ta reda på vad längd s är.
Jag kunde ha lagt det i slingan utan jag bara lägga ut det här för tydlighetens skull.
Så n lagrar nu längden av den ursprungliga strängen, som tydligen 5.
Sedan i min for-slingan jag iteration från 0 på upp till n,
och på varje iteration Jag sätter s [i] inuti t [i].
Så det är vad jag antydde med min 2 fingrar pekar på strängarna innan.
Eftersom detta för slinga itererar så här, jag kommer att kopiera H in på här,
e in på här, jag in på här eftersom det är s, är denna t.
Och sedan slutligen, i linje 35 varför gör jag detta?
Jag måste se till att jag slutar strängen t.
Och jag gjorde det här sättet att vara super tydlig.
Men föreslå någon, om du kunde, ett annat sätt att göra detta.
Jag behöver egentligen inte linjen 35. Det finns ett annat sätt att göra detta.
Ja. >> [Ohörbart elev svar] >> Säg det högre.
[Studerande] Mindre än eller lika med. >> Exakt.
Vi kan bara säga mindre än eller lika med n, som i allmänhet har varit dålig
eftersom nästan alltid när vi går upp till en lika sak vi räknar
vi går 1 steg för långt.
Men kom ihåg, hur många byte vi fördela?
Vi tilldelade strlen av s, så 5 + 1 för totalt 6.
Så i det här fallet kunde vi göra något liknande
så att vi kopierar inte bara hej utan även \ 0 i slutet.
Alternativt kan vi använda en funktion som kallas str kopia, strcpy,
men det skulle inte vara nästan lika kul.
Men det är allt den gör under huven.
Då slutligen gör vi samma sak som tidigare.
Jag kapitalisera t och då jag påstår att den ursprungliga ser ut så här och kopian ser ut som.
Så låt oss prova detta nu. Låt mig gå in här. Gör copy2. Vi ska zooma in och köra copy2.
Jag ska skriva in hej med gemener, och faktiskt jag gemener hej som originalet
men kapitalet Hej för kopian.
Men jag är inte klar ännu. Jag behöver göra en sista sak här.
46 och 47 är klart frigöra minne, men vad betyder det egentligen?
Vad gör jag, tror du, genom att ringa linjen 46 och linje 47?
Vilken effekt har det? Ja.
[Ohörbart elev svar] >> Exakt.
>> Du är bara berättar operativsystemet, hej, tack för detta minne.
Du kan nu använda den för någon annan.
Och här är ett perfekt exempel på sopor värden.
Jag har bara använt detta minne för att skriva ner ordet hej i 2 platser,
här, här, här och här.
Så detta är h-E-L-L-O-\ 0.
Men sedan jag telefonlinje 46 och linje 47, och du vet vad som händer där i form av bilden?
Egentligen, vänta, den här bilden är det gamla.
När vi gör kopian är den här killen pekar faktiskt här,
så låt oss ta bort siffrorna och bara abstrakta bort som våra pilar igen.
Vad händer i den här bilden när jag ringer gratis?
[Ohörbart elev svar] >> Inte ens.
Om jag ringa gratis på s och t - typ av en kuggfråga - bilden inte ändras alls
eftersom ringa s och ringer t talar bara operativsystemet,
hej, kan du använda det här minnet igen, men det förändrar inte det till noll
eller några speciella karaktär ändras inte detta,
Det ändrar inte h eller e eller l eller l eller o antingen plats för något annat.
När det gäller bilden så fort du ringer gratis, ingenting förändras.
Och däri ligger ursprunget till sopor värden för om jag senare i detta program
be operativsystemet för mer minne med GetString eller malloc eller något liknande
och operativsystemet säger visst, jag har 12 byte minne bara frigörs,
använda dessa, vad kommer att överlämnas?
Du kommer att lämnas en bit av minne som vi normalt skulle göra
med frågetecken, men vad är de frågetecken?
De råkar vara H-E-L-L-O, H-E-L-L-O.
Dessa är våra nya sopor värden så fort du frigöra detta minne.
>> Det finns en verklig värld konsekvenser även här.
Det händer att göra med RAM-minne, men dina datorer
faktiskt göra samma sak med disk.
Vi pratar om det här i synnerhet med framtida problem uppsättning som fokuserar på kriminalteknik.
Men vad händer egentligen om du har några känslig finansiell fil på skrivbordet
eller någon skissartad JPEG och du drar den till papperskorgen,
vad som händer när du drar den till papperskorgen eller papperskorgen?
Du visste vad jag pratade om. [Skratt]
Vad händer när du har dragit denna bevisning i din papperskorg eller soptunna?
[Ohörbart elev svar]
Tja, så var försiktig. Vad händer när du gör det?
Det korta svaret är ingenting, eller hur?
Sketchy eller känsliga filer är fortfarande bara sitter där någonstans i din hårddisk.
De flesta av oss åtminstone ha lärt sig den hårda vägen att du måste tömma papperskorgen
eller papperskorgen för att verkligen radera filer.
Och faktiskt, när du högerklicka eller kontrollera klick på papperskorgen
eller välj Arkiv, Töm papperskorgen eller vad
och du tömmer faktiskt papperskorg eller papperskorgen, vad som egentligen händer då med den här bilden?
Mer ingenting. Så att inget händer faktiskt på disken.
>> Och om vi bara tillfälligt avvika och skriva - Jag ska bara använda baksidan av denna.
Så nu berättelsen förändras från RAM, som är där program finns
medan du kör dem, till disk, som är där de lagras lång sikt
även när strömmen går ut, för nu - och vi ska återkomma till detta i framtiden -
Låt oss låtsas bara att detta är hårddisken inuti datorn
eftersom förr i tiden de brukade vara cirkulära skivor, ungefär som disketter.
Så om du har några känsliga Excel-fil, kan det ta upp denna bit av minne
på datorns hårddisk, och jag bara dra samma godtyckliga 1s och 0s.
När du drar filen så där till din papperskorg eller Papperskorgen,
bokstavligen ingenting händer eftersom Apple och Microsoft har just beslutat
papperskorgen och papperskorgen är egentligen bara en tillfällig platshållare.
Kanske så småningom OS kommer tömma det för dig, men typiskt, inte göra någonting,
åtminstone tills du är riktigt ont om utrymme.
>> Men när du går till Töm papperskorgen eller Töm papperskorgen,
liknande händer ingenting i denna bild.
Allt som händer är någon annanstans på datorn, finns det någon form av tabell.
Det är ungefär som en liten lathund som säger att, låt oss säga, resume.doc,
så ditt CV i ett Microsoft Word-fil som används för att leva på plats 123 på hårddisken,
inte i minnet och inte i RAM utan på hårddisken,
och dina skissartade JPEG bor på 456, och din Excel-fil bor på 789 eller varifrån.
När du tar bort filer genom att faktiskt tömma papperskorgen eller papperskorgen,
bilden ändras inte. Den 0 och 1 på hårddisken inte gå någonstans.
Men denna tabell, denna lilla databas av slag, gör förändring.
När du tar bort ditt CV är det som om filen tas bort i någon mening,
men alla Datorn glömmer är där den där saken lever på din hårddisk.
Den 0 och 1 som komponera ditt CV eller några av dessa andra filer är fortfarande intakt.
>> Så om du gjorde detta av misstag, det finns fortfarande en icke-noll sannolikhet
att du kan återställa dina data med Norton Utilities eller någon kommersiell programvara
vars syfte i livet är att hitta 0 och 1 som typ av blivit föräldralösa,
glömt här men kvar här, så att du kan få dina data tillbaka.
Eller kriminaltekniska utredare med polisen eller FBI skulle faktiskt ta en hårddisk
och faktiskt leta efter mönster av 0 och 1 som ser ut som JPEG, ser ut som Excel-filer,
och återställa dem så även om datorn har glömt dem där.
Så det enda sättet att verkligen ta bort data, som vi kommer att diskutera i framtiden,
är att skrubba eller torka filen eller hårddisken -
Du kan inte riktigt bli av med 0 och 1
annars skulle du börja med en gigabyte hårddisk
och du skulle sluta med en megabyte hårddisk om du ständigt skulle bort,
bokstavligen, 0 och 1.
Så vad skulle du göra om du verkligen ville täcka dina spår
och det grundläggande problemet är att det finns fortfarande 0 och 1 på disken?
Jag ser någon gestikulerade att du fysiskt skulle bryta enheten. Det kommer att fungera.
[Skratt] Men om det är typ av en dyr lösning, vad skulle vara mer rimligt?
Ja. >> [Elev] Skriv över dem. >> Överskrivning dem med vad? >> [Elev] Övriga uppgifter.
Andra data. Du kan bara skriva din disk med 0s eller 1s eller alla 0: or, alla 1s.
>> Och det är faktiskt vad vissa av programvaran gör.
Du kan köpa programvara eller ens få fri programvara,
och även inbyggt i Mac OS nuförtiden, mindre i Windows,
är förmågan att säkert radera.
Egentligen, om du vill alla kör hem idag om du har en Mac och göra detta,
om du har lite grejer i din papperskorg, kan du göra säker Töm papperskorgen,
som gör just detta.
Snarare än att bara radera filer här, inte radera den inte 0 och 1 här,
Snarare ändrar den bara dem alla, t.ex. för att 0s och punkt, punkt, punkt.
Så en av dina framtida psets faktiskt kommer att vara att avsiktligt återställa data -
fotografier som vi har tagit av människor, platser och saker på campus
som vi ska göra en rättsmedicinsk bild av en digitalkamera minneskort,
vilket är exakt samma idé - och du måste utmanas att faktiskt hitta
de mönster som representerar JPEG på din hårddisk,
ungefär som att tidigare student vars e-post jag läste för några veckor sedan gjorde
att återvinna sin systers fotografier.
Varför tar vi inte en 5-minuters paus här, och vi kommer omgruppera med mer på minnet.
Så här är där det blir lite kluriga, men detta är en mycket kraftfull steg
till att förstå detta desto mer.
Här är ett program som heter pointers.c.
Det är bland dagens exempelkod.
Observera att i de första raderna, 19 till 22, är allt vi gör något liknande GetString
och returnera en adress, lagra den i s..
Hädanefter för pset även 3 om du vill men pset 4 och på
där du kan börja ta dessa stödhjul utanför dig själv,
finns det ingen anledning att låtsas att strängar finns längre.
Det är verkligen okej att bara börja säga char *.
>> Som en sidoreplik, i online referenser och i böcker kan ofta se stjärnan bredvid variabel.
Du kan även se utrymmen runt båda sidor.
Alla dessa är funktionellt korrekta.
För nu, men vi standardisera på denna metod för att göra Super Clear
att char * är som att säga karaktär pekare.
Det är datatypen.
Och sedan namnet på variabeln är s i detta fall.
Så vi har fått en sträng och vi har kallat det s.
Och sedan ner hit märker att jag gör faktiskt lite knep.
Detta kallas pekare aritmetik, vilket är en slags super enkelt.
Det betyder bara addera och subtrahera tal till pekare.
Men detta fungerar faktiskt.
Detta program skriver tydligen strängen s 1 tecken per rad så att slutresultatet -
Bara så vi kan förstöra där detta går, göra pekare, köra pekare, låt mig zooma in
Låt mig typ i något som hej och typ Enter
och det skrivs 1 tecken per rad.
Fram till för en sekund sedan, skulle vi ha gjort detta med hakparentes notation.
Vi skulle ha en for-slinga, och vi skulle göra printf av s [i] och vi skulle göra det igen och igen och igen
med ett omvänt snedstreck n vid slutet av varje rad.
Men detta program är annorlunda. Detta program använder, bokstavligen, aritmetik.
Så vad händer här?
Först av allt, innan denna slinga ens körs, vad, bara för att vara tydlig, är s egentligen?
S är? >> [Elev] En adress. >> En adress.
>> Och det är adressen, i fallet med hej, det första tecknet i det ordet, vilket är h..
Så s är, i detta särskilda exempel, adress timmar.
Så vad innebär det att göra s + i?
Tja, börjar jag i 0 i detta for-slinga. Vi har gjort det många gånger.
Jag kommer att gå upp till längden på strängen, tydligen.
Så på den första iteration av denna slinga är jag naturligtvis 0.
Så detta uttryck säger s + i - snarare s +0--det är uppenbarligen bara är.
Så vad är * är här?
Nu vi använder stjärnan i ett något annorlunda sätt.
Låt mig gå vidare och bli av med t eftersom vi är klara talar om t och kopior av s.
Nu vill vi bara att berätta en historia där s.
Och så i detta ögonblick, efter att ha typen String, ser vår värld helt som det gjorde innan
med bara s lagra adress h och mer allmänt pekar på strängen hej.
Om jag nu gör en rad som * (s + i), låt oss prova detta.
Så * (s + i). Låt mig förenkla detta eftersom det är 0, så detta är * (S +0).
Jo, vänta en minut. Ytterligare förenkla. Detta är * (er).
Nåväl, nu parentes är typ av dum, så nu ska vi bara göra * s.
Så i det första variant av denna slinga, den linjen som är markerad, 26,
är ganska mycket motsvarar skriva detta.
Vad är datatypen för * s?
I detta sammanhang, eftersom stjärnan råkar vara bredvid s själva,
men mer specifikt, eftersom vi inte längre förklara s
vi inte skapar en variabel längre, det finns inget omnämnande av char * i linje 26,
Det finns inget omnämnande av sökordet strängen använder vi bara en variabel som heter s,
det visar sig nu stjärnan har något annorlunda och visserligen förvirrande mening.
* S betyder här att gå till adressen i S och skriva ut allt finns där.
Så s är här, * s - ungefär som rännor och stegar, följ pilen - här.
Så detta är * s.
>> Så vad blir tryckt på den första iteration av den slinga i linje 26?
Jag skriver ut% c, som är platshållare för ett tecken,
sedan en \ n för en ny linje. * (S + i) där i är 0 är just detta.
Så vad röding lägger jag in för% c? H.
I nästa iteration av slingan - du kan nog se vart detta kommer -
nästa iteration i är uppenbarligen 1, så detta innebär s +1,
och så nu jag behöver parenteserna för nu stjärnan behöver säga
gå till minnesadress s +1.
Vad är s? Låt oss rulla tillbaka i tiden och säga detta pil nu faktiskt inte gör oss några favörer.
Låt oss mer specifikt säga att detta lagrar numret 123
eftersom starten av denna sträng hej, är denna adress 123, är denna 124, och så vidare.
Så på den andra iterationen när jag säger er en, det är som att säga 123 1,
annars känd som 124, så vad röding blir tryckt på den andra iterationen?
E vid minnesadress 124.
Då + igen, 125, 126, 127, och denna slinga slutar tack och lov innan vi får här
eftersom jag använder strlen att se till att jag inte räknas för högt.
Så det är också det.
Återigen, detta är bara som om vi hade gjort en vecka sedan.
Låt mig skriva det på raden under, även om vi inte vill göra båda.
Detta är identiskt nu detta.
>> Så även om s är en sträng, som vi har kalla det i veckor, är är verkligen en char *.
Så om vi vill vara super anal, det är verkligen lämpligt att skriva den särskilda karaktären
vid den i: te platsen med hjälp av dessa numeriska adresser och denna stjärna operatör,
men ärligt talat, det är bara så mycket renare. Så detta är inte dåligt.
Ingen anledning att sluta göra linjen 27 här, men 26 är funktionellt densamma,
och det är funktionellt samma för exakt de skäl som vi har diskuterat hittills.
Och slutligen, är 29 bara god praxis.
Ringa gratis s innebär att du nu är att ge tillbaka det minne som GetString gav dig
eftersom igen, som jag nämnde måndag, getString flera veckor
har inför en bugg i koden.
Din kod i veckor haft minnesläckor
där du har begärt GetString för minne, men du har aldrig varit att ge det tillbaka.
Och det medvetet valdes av oss pedagogiskt
eftersom det är alldeles för mycket att tänka på ett tidigt stadium.
Men nu behöver vi mer symmetri.
Om du frågar datorn för minnet, vilket är fallet för GetString,
såsom är fallet uppenbarligen för malloc,
måste du nu för pset 4 framåt också gratis sådan minne.
Notera att detta är annorlunda från att säga int n.
Du behöver inte att befria detta eftersom du inte ringde GetString
och du inte ringa malloc.
>> Och även om du heter getInt som vi kommer så småningom se,
GetInt inte allokera inte minne för dig eftersom du faktiskt kan skicka runt heltal
och flyter och tecken precis som vi har gjort i flera veckor.
Strängar, men är speciella eftersom verkligen att de är sammanlänkningen av flera tecken.
Så de är bara annorlunda tecken, flyter och Ints och liknande.
Men vi kommer tillbaka till det inom kort.
Eventuella frågor sedan om detta i början av pekare? Ja.
[Ohörbart elev fråga]
Ah, mycket bra fråga.
En av de få saker som C faktiskt gör för dig, som är bekvämt,
är det siffror för dig vilken storlek är av datatypen
och gör då den typen av multiplikation för dig.
Detta är irrelevant i fråga om tecken eftersom nästan alltid en röding är 1 byte,
så detta fungerar bara.
Men för den skull diskussionen, om du verkligen skriva heltal
och du försöker skriva ut ett visst värde är som pekade på ett heltal,
Du heller inte skulle behöva göra + 4 * jag bara för att en int är 4 bytes.
Pointer aritmetiska innebär att C och kompilatorn göra allt matematik för dig.
Allt du behöver bry sig om är räkningen i form av den mänskliga förnuft. Ja.
[Elev] Om du deklarerar en sträng i en for-slinga, har du att frigöra den senare?
Bra fråga.
>> Om du deklarerat en sträng inne i for-slingan, behöver du frigöra det senare?
Du behöver bara att frigöra minne som du fördela med GetString eller malloc.
Så om du bara säga något i stil - låt mig ställa klammerparenteser nu så all kod är relaterad.
Om du gjorde något, om än buggily, så här, char * t = s,
du behöver inte fria t eftersom t inte innebar någon omnämnande av malloc eller GetString.
Om däremot du gjorde det, GetString, så ja, skulle du behöva fri t.
Och i själva verket är din enda chans att göra det nu inuti denna slinga, för samma nummer av omfattning
att vi har diskuterat tidigare.
Annars skulle du vara fördela minne, fördela minne, fördela minne,
och i slutet av programmet eftersom du är utanför den slinga,
t finns inte, men du har aldrig berättat operativsystemet
att du inte behöver att minnet längre.
Och snart för pset 4 eller 5 kommer vi förse dig med ett program som heter Valgrind,
som likadana i andemening som GDB att det har fått något av en hemlig gränssnitt,
men dess syfte i livet är att hjälpa dig.
Och Valgrind är ett program som i framtiden kommer att söka dina program
söker minnesläckor, oavsett om GetString eller malloc,
som vi börjar använda allt mer som vi slutar använda CS50 biblioteket så mycket.
Vi har äntligen nu slags ordförråd och den typ av mental modell i teorin
som att lösa detta brutna programmet.
>> Så i detta brutna programmet, fungerar swap inuti swap,
men det aldrig fungerat i huvud eftersom huvud gick i x-och y, återkallande,
och de antogs i av värden, så att säga.
Kopior av dem gavs att byta.
Vid slutet av swap hade a och b faktiskt bytts,
men naturligtvis x och y, som vi diskuterade på måndagen, inte hade varit.
Så jag föreslår i grönt här att detta är faktiskt en lösning här.
Och faktiskt, låt mig flytta mina stjärnor bara för att vara konsekvent
även om, återigen, funktionellt detta ingen roll.
I framtiden veckorna kommer vi att förklara när och varför det spelar roll.
Så i grönt nu är en lösning.
Ärligt talat, det ser en hel del Messier eftersom jag har alla dessa stjärnor.
Låt mig påpeka en sak.
Den översta raden här där det står int * a och int * b
är i grunden gör samma sak som det alltid har gjort.
Det förklarar 2 argument eller parametrar att byta,
av vilka den första är en int pekare kallas,
den andra är en int pekare som heter b..
Det enda som är nytt på denna punkt är det faktum att det finns en stjärna där.
>> Vad betyder det? A är inte en int, är b inte en int.
A är adressen till en int och b är adressen till en annan int.
Här nere är det här jag erkänna C blir förvirrande.
Nu vi använder en stjärna, men det har olika innebörd i detta sammanhang.
Eftersom vi inte förklara tips som vi är här uppe,
Här är vi dereferencing saker.
Så tekniskt, stjärnan i detta sammanhang för den första, andra och tredje raden inuti swap
är att gå på dereference aktör och som bara innebär att det.
Så precis som fingret följde på pilen för att h
* Ett sätt att gå till den adressen och hitta mig int som finns där.
* B innebär gå till adressen och skicka mig vad som finns där.
Så låt oss rita bilden från måndag nu med en bunt ramar,
den nedre av vilka kommer att vara huvud,
den övre av vilka kommer att vara swap,
så att vår värld ser ut precis som måndag, så här.
Här är en bit av minne som främsta kommer att använda.
>> Minns måndag att programmet bara hade 2 variabler,
en som heter X och en som heter y och jag hade lagt siffrorna 1 och 2.
Nu när jag ringer byta som jag gjorde i måndags,
tidigare när jag använde den röda versionen av programmet, ser som så här,
Jag fick 2 parametrar, a och b, och vad gjorde vi skriver här och här?
Bara 1 och 2, bokstavligen kopior av x och y..
Idag har vi ändra på det.
Idag istället för att passera i Ints a och b ska vi passera i 2 adresser.
Dessa adresser råkar peka vare sin, men dessa adresser inte Ints själva.
De är adresser. Det är som en postadress i stället.
Så nu måste vi bara ge mig själv lite mer i detalj på skärmen.
Det här är min dators minne som det har varit hela dagen.
Nu behöver vi någon godtycklig numrering system.
Så låt oss bara säga, bara av en slump, att detta är minnesadress 123, 124.
Låt oss bara säga att detta är 125, det är 126, och så vidare, men det är helt godtycklig.
Vi behöver bara lite numrering i mitt minne.
Så nu när jag faktiskt passera i x och y, jag kommer inte att passera i x-och y;
Jag ska passera i postadress, så att säga, av x och y
så att det får lagras här och här är inte 1 och 2,
men om du kan se min lilla text får vad gick in här och här?
[Ohörbart elev svar] >> Exakt. 123 får sätta här och 124 får sätta här.
>> Nu, eftersom jag använde stjärnan i denna allra första raden upp här på toppen,
mitt program vet bara att 123 och 124, även om de är uppenbarligen heltal
att någon människa skulle kunna märka, bör de tolkas som adresser, numeriska adresser.
De är inte i sig själva Ints, de är adresser,
och det är för att jag har uttryckligen sätta stjärnor där.
Så nu i min första, andra och tredje raden av faktiska koden vad som händer här?
Låt oss dra resten av bilden.
Tmp är precis som det var på måndag. Inget särskilt om tmp.
Det är bara en lokal 32 bitar variabel och inuti att jag tydligen lagra värdet av * en.
Nu, om jag bara sagt tmp = a, vad skulle jag sätta här? >> [Elev] 123.
123. Men det är inte vad jag gör.
Jag säger tmp = * en. Star medel dit.
Så här är en, 123. Hur går jag dit? Låtsas som det finns en pil.
Tja, det är det, 1. Så vad får lagras i tmp, tydligen? Bara 1.
Så med andra ord är TMP * a, * ett sätt att gå till den adress som befinner sig i en,
vilket är tydligen 123.
>> Okej, här är vi på plats 123, ser jag siffran 1,
så jag ska sätta siffran 1 där.
Nu vad gör jag i linje 2, * a = * b?
Den här är lite mer engagerade för nu vad som är en? Det är 123.
Så * en är där? Precis där jag var innan. Så gå dit. Okej.
Nu slutligen och slutligen det börjar vettigt, förhoppningsvis,
* B betyder vad som finns i b? 124. Så jag måste gå dit, vilket är 2.
Så vad lägger jag var?
2 går in här eftersom * b går in * en. Så jag ska göra det.
Och du kan redan se, kanske att vi är så mycket närmare
att lösa detta dumma, enkla problem korrekt för första gången
för nu har vi fortfarande ett minne av vad X var,
Vi har 2 kopior visserligen av y,
men linje 3 säger nu * b.
Så här är b.. * B innebär dit. Så var är platsen 124?
Det är tydligen här. Så vad lägger jag här? Uppenbarligen, tmp.
Så nu gör jag det. Så jag har en här och 2 här.
Och nu vad om allt detta, 123, den 124 och 1?
Så snart swap återvänder, är detta minne så gott som förlorad
eftersom så snart swap avkastning, operativsystemet
är fri att använda minnet igen i framtiden.
Endast viktigaste minne längst ner på denna så kallade stack sticker runt.
>> Och så har vi äntligen nu en fungerande version.
Låt mig gå in swap.c, och märker följande.
På toppen av det program jag har ändrat min prototyp som int * a och int * b..
Så det enda jag bytt för att gå från rött, som var dåligt, till grönt, vilket är bra,
är jag lagt dessa stjärnor i dag.
Men sedan här i byta själv var jag tvungen att kopiera, klistra det var bara på bilden.
Jag har en stjärna här, stjärnan här - som matchar prototypen -
och sedan alla dessa saker nu stjärnor utom TMP
eftersom användningen av en temporär variabel, det är inget nytt där.
Jag behöver bara tillfällig förvaring för en int.
Så vi behöver inte en stjärna där.
Vi behöver bara stjärnan så att vi kan korsa den här typen av godtyckliga gräns
mellan dessa 2 bilder i min dators minne.
Men en sista sak måste förändras, och du kanske har skymtat det redan.
Vilka andra linjen är naturligtvis annorlunda nu? >> [Elev] & x.
>> Ja, så 25 sista kodraden jag behöver ändra för att det ska fungera.
För en vecka sedan och även på måndag linje 25 såg ut så här, byta x och y,
och detta var bara bröts för om du säger swap (x, y)
du ger kopior av x och y för att byta, så det gör sin grej,
men du aldrig faktiskt förändras x-och y självt.
Så även om du aldrig har sett denna karaktär innan med et-tecknet i koden,
bara ta en gissning. Vad gör et-tecknet, tydligen?
[Elev] Europaparlamentet adressen. >> Europaparlamentet adressen.
Så et-tecknet säger ge mig adressen till x.
Vem vet var det är? Det råkar vara 123. Jag bryr mig inte. Ge mig adressen till x.
& Y betyder ge mig adressen till y..
Och vid den tidpunkten berättelsen är helt förenligt med den bild vi drog för en stund sedan.
>> Så jag ska erkänna pekare, säkert för mig när jag först började lära mig detta,
var definitivt en av de svåraste sakerna att linda mig runt.
Men inser, särskilt som vi håller att leka med sådana här saker,
Om du bryter ner det till dessa super enkla typ av intellektuellt ointressant problem
att bara flytta siffror runt, svaret på en hel del förvirring med pekare
verkligen kan härledas från dessa mycket grundläggande mekanik.
Här är en adress. Gå dit med stjärnan.
Eller omvänt, här en-tecken. Räkna ut vad adressen egentligen är.
Okej.
Så där är allt detta minne kommer från?
Vi har ritat den här bilden ett par gånger, och jag håller lovande att vi ska komma tillbaka till det,
men här är representationen av datorns minne
Det är lite mer märkt än vår svarta tavlan här är.
Texten segmentet överst representerar vad när det gäller ditt program?
[Ohörbart elev svar] >> Ursäkta? Säg igen.
[Elev] själva programmet. >> Själva programmet.
>> Så 0s och 1s att du har sammanställt efter att ha skrivit C-kod och sedan köra klang
och generera 0 och 1 avslutar upp att få stoppade det i minnet
eftersom när du dubbelklickar på en ikon på din Mac eller PC
eller köra ett kommando som Mario i din prompt, din 0 och 1 från disk
få laddas in i minnet så att datorn kan manipulera dem
och verkställa dem snabbare.
Så initierade data och oinitierade uppgifter kommer vi att tala inte mycket om dem,
men de är bara globala variabler.
Initierat betyder globala variabler som du gav värden;
oinitierad betyder globala variabler som du ännu inte gav värden.
Sedan finns dessa miljövariabler som jag ska helt våg min hand på,
men de finns där och som lagrar saker som ditt användarnamn
och andra slags lägre nivå detaljer.
Men de saftigaste bitarna av ditt minne layout är denna sak kallad stapeln och högen.
Stapeln igen, att vara tydlig, är minnet som används när funktioner kallas,
när det finns lokala variabler
och när det finns parametrar som skickas runt.
Allt som händer i stapeln.
Högen vi inte pratat om, men ta en gissning som använder högen.
Bara en annan bit av minnet.
Det händer att dras här på toppen, men det är en godtycklig illustrerad konvention.
Vem tydligen använt minne från högen i veckor?
Det är tekniskt dig men indirekt. >> [Elev] GetString.
GetString och malloc. Så här är den grundläggande skillnaden.
>> Du vet de senaste veckorna att om du behöver minne, deklarera en variabel.
Om du behöver massor av minne, förklarar en rad rätt inne i din funktion.
Men problemet vi har hållit inför är om du deklarerar variabler lokalt inuti funktioner,
så snart som funktionen returnerar, vad händer till minnet och de variabler?
Bara sorts det inte längre din, eller hur? Det försvinner bara typ av konceptuellt.
Det är fortfarande fysiskt där, naturligtvis, men det är inte längre din rätt att använda.
Detta är naturligtvis problematiskt om du vill skriva funktioner i livet
som faktiskt allokera minne och inte ge det tillbaka omedelbart.
Ett typexempel: GetString s syfte i livet är att inte ha någon aning i förväg
hur stor av en sträng ska jag skriva på tangentbordet,
men det måste kunna allokera minne för att hålla David eller hej
eller en hel uppsats som användaren kan ha skrivit in
Så GetString har använt malloc.
Malloc måste därför använder inte stacken,
i stället är det med denna sak som kallas högen.
Det finns inget annat om minnet. Det är inte snabbare eller långsammare eller nåt sånt.
Det är bara fysiskt på en annan plats.
>> Men regeln är att minnet som är fördelas på högen
kommer aldrig tas ifrån dig tills du anropar - ta en gissning - gratis.
Däremot något minne du ber om på stacken genom att bara förklara en rad
eller förklara en variabel som vi har gjort i flera veckor,
att som standard hamnar på stacken.
Och det fungerar bra 90% av tiden, men på de mer sällsynta tillfällen
där du vill allokera minne och hålla den runt,
då du behöver använda en funktion som malloc.
Eller har vi använt en funktion som GetString, vilket i sin tur använder malloc.
Låt oss se om detta kan bryta ner och sedan ta en titt på Binky.
Vi ska återkomma till detta i framtiden.
Här är en super enkelt program som i de första 2 rader gör vad?
På engelska, vad dessa första 2 rader kod gör inuti huvud?
[Ohörbart elev svar]
Försiktig. Det ger inte mig adressen till x eller y..
[Elev] Ger pekare vare sin. >> Bra. Ge mig 2 pekare till heltal.
Med andra ord, ge mig 2 bitar av minne som jag håller teckning idag,
även om jag raderat det nu, som fyrkanter.
Ge mig 2 bitar av minne, som kallas en x, som kallas en y -
tidigare jag kallade dem s och t - och vad som är den typ av denna bit av minnet?
Det kommer att lagra en adress.
Det är av typen int *.
>> Så adressen för en int kommer så småningom leva i x,
adressen för en int kommer så småningom leva i y,
men i början, vad är inne i x-och y? Vem vet? Garbage värden.
Det har ingenting att göra med pekare.
Om vi ​​har inte satt något där, vem vet vad egentligen där?
Nu, X. Vad händer här? Detta är legit nu eftersom x är en pekare. Det är en int *.
Så det betyder att jag kan sätta i x adressen av någon bit av minnet.
Vad återvänder malloc? Perfekt, returneras adresser,
adressen för den första bitgruppen i en hel bit av minne.
Hur många byte detta fördela tydligen, till exempel i skåpet?
Vad är storleken på en int? 4.
Om du tänker tillbaka på vecka 1, det är inte super viktigt att alltid komma ihåg att,
men i detta fall är det bra att veta, 4 byte.
Så detta avsätter på heap 4 byte
och det återvänder adressen för den första att mig godtyckligt.
Nu, vad X gör?
A * x = 42 som gör vad?
Om det vid denna punkt i berättelsen har vi x, som ser ut så här med några skräp värde,
detta är nu y med vissa skräp värde, nu i linje 3 Jag har tilldelats 4 byte.
Denna bild ser huvudsak så här.
Eller mer specifikt, om detta är godtyckligt adress 123, det är vad vår berättelse nu ser ut.
* X = 42 nu betyder vad? Det innebär att gå till adressen 123 och uppskattar antalet 42 där.
Jag behöver inte dra dessa linjer eftersom vi inte gör strängar.
>> Jag borde ha just skrivit det så här, och bara för demonstration skull,
42 som en int typ av tar upp mycket utrymme, 4 byte.
Så det är vad som har hänt där, men det finns ett problem nu.
* Y = 13. Vad kommer att hända här?
Problemet är * y i vår förenklade värld betyder bara att gå till adressen i y..
Vad finns i Y? Det är lite sopor värde.
Så låt oss anta att det skräp värde är 5551212, något galet så.
* Y betyder Gå till adress 5.551.212.
Det är som här. Det finns inte, till exempel.
Så * y blir 13 betyder jag försöker dra 13 här. Det existerar inte.
Jag har överskridit segment av tavlan. Vad får jag?
Det kryptiskt meddelande segmenteringsfel eftersom jag försöker sätta i minnet
ett värde som 13 på en plats som inte finns.
Resten av programmet kan fungera okej, men fram till den punkt det inte.
Så låt oss försöka att berätta den här historien.
Vi ska återkomma till detta när vi har pratat om hex.
Låt oss gå tillbaka till detta och avsluta med denna sak som kallas Binky,
vilket minns är en Stanford professor sitter hemma leker med Claymation,
att berätta historien om exakt samma program.
Det är bara ca 3 minuter långa. Här har vi Binky.
[Manlig talare på video] Hey Binky, vakna. Det är dags för pekaren kul.
[Binky] Vad är det? Lär dig mer om pekare? Åh, karamell!
[Manlig talare] Jo, för att komma igång, jag antar att vi kommer att behöva ett par tips.
>> [Binky] Okej. Denna kod tilldelar 2 pekare som kan peka till heltal.
[Manlig talare] Okej. Jag ser de 2 pekare, men de verkar inte vara att peka på någonting.
[Binky] Det stämmer. Inledningsvis tyder pekare inte till någonting.
De saker som de pekar på kallas pointees, och ställa upp dem är ett separat steg.
[Manlig talare] Åh, höger, höger. Jag visste det. De pointees är separata.
Er, så hur tilldela dig en pointee?
[Binky] Okej. Denna kod tilldelar en ny heltal pointee, och denna del set x peka på den.
[Manlig talare] Hej, det ser bättre ut.
Så gör det att göra något. >> [Binky] Okej.
Jag ska dereference pekaren X för att lagra numret 42 i sin pointee.
För detta trick jag behöver min trollstav av dereferencing.
[Manlig talare] Din trollstav för dereferencing? Det är bra.
[Binky] Detta är vad koden ser ut. Jag ska bara ställa in antalet och ... [Popping ljud]
[Manlig talare] Hej titta, där det går.
Så gör en dereference på x följer pilen för att komma åt sin pointee,
i detta fall för att lagra 42 där.
Hej, prova att använda den för att lagra numret 13 genom den andra pekaren, y.
[Binky] Okej. Jag ska bara gå hit till Y och få numret 13 inrättat
och sedan ta staven av dereferencing och bara ... [Surrande ljud] Whoa!
[Manlig talare] Åh hej, kom det inte fungerar.
>> Säg, Binky, jag tror inte dereferencing y är en bra idé
eftersom inrättandet av pointee är ett separat steg
och jag tror inte att vi någonsin gjorde det.
[Binky] Hmm, bra poäng.
[Manlig talare] Ja. Vi tilldelades pekaren y, men vi har aldrig satt det att peka på en pointee.
[Binky] Hmm, mycket uppmärksam.
[Manlig talare] Hej, du ser bra där, Binky.
Kan du fixa det så att y pekar på samma pointee som x? >> [Binky] Visst.
Jag använder min trollstav av pekare uppdrag.
[Manlig talare] Är det kommer att bli ett problem som förut?
[Binky] Nej, detta inte vidrör pointees.
Det förändrar bara en pekare att peka på samma sak som en annan. [Popping ljud]
[Manlig talare] Åh, ser jag. Nu y pekar på samma plats som x.
Så vänta. Nu y är fast. Den har en pointee.
Så du kan prova staven för dereferencing igen för att skicka 13 över.
[Binky] Eh, okej. Här går. [Popping ljud]
[Manlig talare] Titta på det. Nu dereferencing fungerar på y..
Och eftersom pekare delar att en pointee de båda se 13.
[Binky] Ja, delning. Oavsett.
>> Så ska vi byta plats nu?
[Manlig talare] Oh titta, vi är ute i tid. >> [Binky] Men -
[Manlig talare] Kom bara ihåg de 3 pekaren reglerna.
Nummer 1 är den grundläggande strukturen att du har en pekare och det pekar på en pointee.
Men pekaren och pointee är separata, och vanligt fel är att inrätta en pekare
utan att glömma att ge det en pointee.
Nummer 2 börjar pekaren dereferencing på pekaren och följer dess pil över
att få tillgång till dess pointee.
Som vi alla vet, detta fungerar endast om det finns en pointee,
vilken typ av kommer tillbaka till regel nummer 1.
Nummer 3, tar pekaren uppgift en pekare och ändrar den
att peka på samma pointee som annan pekare.
Så efter uppdraget kommer de 2 pekare peka på samma pointee.
Ibland kallas delning.
>> Och det är allt som finns att det verkligen. Hejdå nu.
Detta är Binky. Detta är CS50. Vi ses nästa vecka. [Applåder]
>> [CS50.TV]