[Powered by Google Translate] [AFSNIT 5: mindre behagelig]
[Nate Hardison, Harvard University]
[Dette er CS50.] [CS50.TV]
Så velkommen tilbage, gutter.
Velkommen til punkt 5.
På dette tidspunkt, har afsluttet quiz 0 og efter at have set, hvordan du har gjort
forhåbentlig du føler virkelig godt, fordi jeg var meget imponeret over de scorer i dette afsnit.
For vores online seere, vi har haft et par spørgsmål
om de sidste to problemer på det problem sæt - eller på quiz, snarere.
Så vi kommer til at gå over dem virkelig hurtigt, så alle ser hvad der skete
og hvordan man kan gå gennem den faktiske løsning snarere end blot at se løsningen selv.
Vi vil gå over de sidste par problemer virkelig hurtigt, 32 og 33.
Just, igen, kan så at de online seere se dette.
>> Hvis du slår til dit problem 32, som er på side 13,
13 ud af 16, problem 32 handler om swaps.
Det var alt om at bytte to heltal.
Det er det problem, at vi var gået over et par gange i forelæsning.
Og her er, hvad vi beder dig om at gøre en hurtig hukommelse spor.
At udfylde værdierne af variablerne, som de er på stakken
som koden går gennem denne swap-funktion.
Især vi, hvad kigger på - jeg vil sætte denne iPad ned -
i særdeleshed, er det, vi ser på denne linje nummereret 6 lige her.
Og det er nummereret 6 for bare sammenfletningen med den tidligere problem.
Hvad vi ønsker at gøre, er at vise eller mærke tilstand af hukommelse
da det er på det tidspunkt, hvor vi udfører denne linje nummer 6,
der er faktisk en tilbagevenden fra vores swap-funktion lige her.
Hvis vi rulle ned her, så vi, at adresserne på alt i hukommelsen blev leveret for os.
Dette er meget vigtig, og vi vil vende tilbage til det i bare et øjeblik.
Og så hernede på bunden, havde vi en lille hukommelse diagram, som vi kommer til at referere til.
Jeg har faktisk gjort det ud på min iPad.
Så jeg har tænkt mig at skifte frem og tilbage mellem iPad og denne kode bare for reference.
>> Lad os starte. Først, lad os fokusere på de første par linjer af main lige her.
Hvis du vil starte, vi kommer til at initialisere x til 1 og y til 2.
Så vi har to heltalsvariabler, er de begge kommer til at blive placeret på stakken.
Vi kommer til at sætte en 1 og en 2 i dem.
Så hvis jeg vende over til min iPad, forhåbentlig, lad os se -
Apple TV spejling, og der går vi. Okay.
Så hvis jeg vende over til min iPad,
Jeg vil initialisere x til 1 og y til 2.
Det gør vi ganske enkelt ved at skrive en 1 i rubrikken x
og en 2 i rubrikken y. Forholdsvis enkel.
Så nu lad os gå tilbage til den bærbare computer, se hvad der sker næste.
Så dette næste linje er, hvor tingene bliver tricky.
Vi passerer adressen på x og adressen på y som parametrene a og b til swap-funktionen.
Adressen på x og adressen på y er ting, som vi ikke kan beregne
uden at henvise til disse punkttegn lige hernede.
Og heldigvis, de to første punkttegn fortælle os præcis, hvad svarene er.
Adressen på x i hukommelsen er 10, og adressen på y i hukommelsen er 14.
Så det er de værdier, der bliver vedtaget i som a og b op top i vores swap-funktion.
Så igen, skifte tilbage til vores diagram, kan jeg skrive en 10 i en
og en 14 i b.
Nu, dette punkt er, hvor vi gå videre med swap.
Så flipping tilbage til den bærbare computer igen,
vi se, at den måde swappen værker er jeg først dereference en og gemme resultatet i tmp.
Så dereference operatør siger: "Hey. Behandl indholdet af variabel en som en adresse.
Gå til det, der er lagret på den pågældende adresse, og indlæse den. "
Hvad du lægger ud af variablen vil blive gemt i vores tmp variabel.
Flipping tilbage til iPad.
Hvis vi går til Adresse: 10, vi ved, at adressen 10 er det varible x
fordi vi fik at vide af vores kugle punkt, at adressen på x i hukommelsen er 10.
Så vi kan gå der, få værdien af ​​det, som er 1, som vi ser på vores iPad,
og indlæse det i tmp.
Igen, dette er ikke det endelige indhold.
Vi vil gå igennem, og vi vil komme til vores endelige udformning af programmet ved udgangen.
Men lige nu har vi værdien 1 gemmes i tmp.
>> Og der er et hurtigt spørgsmål herovre.
[Alexander] Er dereference operatør - det er bare den stjerne lige foran variablen?
>> Ja. Så dereference operatør, da vi vende tilbage til vores bærbare igen,
er denne stjerne lige foran.
I den forstand er det - du kontrast det med multiplikation operatør
der kræver to ting, den dereference operatør er en Monadiske operatør.
Blot anvendes på en værdi i modsætning til en binær operator,
hvor du anvender til to forskellige værdier.
Så det er hvad der sker i denne linje.
Vi indlæst værdien 1 og gemt det i vores midlertidige heltalsvariabel.
Den næste linje, vi gemme indholdet af b ind -
eller rettere, vi gemme indholdet at b peger på i det sted, hvor en peger på.
Hvis vi analyserer dette fra højre til venstre, vil vi dereference b,
vi kommer til at tage 14, vil vi få fat i heltal, der er der,
og så vil vi gå til adressen 10,
og vi kommer til at kaste et resultat af vores dereference af b ind i dette rum.
Spejlvende tilbage til vores iPad, hvor vi kan gøre dette til en lidt mere konkret,
det måske ville hjælpe, hvis jeg skriver tal på alle de adresser her.
Så vi ved, at y, vi er på adressen 14, x er på adressen 10.
Når vi starter på b, vi dereference b, vil vi få fat i værdien 2.
Vi vil få fat i denne værdi, fordi det er den værdi, der bor på adressen 14.
Og vi vil sætte det i variabel, der bor på adressen 10,
der er lige der, svarende til vore variable x.
Så vi kan gøre en lille smule for at overskrive her
hvor vi slippe af med vores 1 og i stedet skriver vi en 2.
Så alle er meget godt i verden, selv om vi har overskrevne x nu.
Vi har gemt x gamle værdi i vores tmp variabel.
Så vi kan færdiggøre ombytningen med den næste linje.
Spejlvende tilbage til vores bærbare.
Nu er alt der er tilbage er at tage indholdet ud af vores midlertidige heltalsvariabel
og gemme dem i den variabel, der bor på den adresse, b holder.
Så vi vil til effektivt at dereference b for at få adgang til den variable
det er på den adresse, b besidder i det,
og vi vil proppe den værdi, tmp holder ind i det.
Flipping tilbage til iPad igen.
Jeg kan slette denne værdi her, 2,
og i stedet vil vi kopiere 1 højre ind i det.
Så den næste linje, der udfører, naturligvis -
hvis vi vende tilbage til den bærbare computer - er dette punkt 6,
som er det punkt, hvor vi ønskede at have vores diagram helt fyldt ud.
Så flipping tilbage til iPad igen, bare så du kan se det færdige diagram,
du kan se, at vi har en 10 i en, en 14 i b, en 1 tmp, 2 i x, og en 1 i y.
Er der nogen spørgsmål om dette?
Giver det mere mening, efter at have gået igennem det?
Gør mindre mening? Forhåbentlig ikke. Okay.
>> Pointers er en meget tricky emne.
En af fyrene vi arbejder med har et meget almindeligt ordsprog:
"For at forstå pegepinde, skal du først forstå pointers."
Hvilket jeg synes er meget sandt. Det tager et stykke tid at vænne sig til det.
Tegning masser af billeder, trækker masser af hukommelse diagrammer som denne meget nyttigt,
og når du går igennem eksempel efter eksempel efter eksempel,
det vil begynde at gøre lidt mere mening og lidt mere fornuft og lidt mere mening.
Endelig en dag, vil du have det hele helt mestrer.
Eventuelle spørgsmål før vi går videre til det næste problem? Ok.
Så vende tilbage til den bærbare computer.
Det næste problem, vi har, er problem nummer 33 på fil I / O.
Zoom ind på dette en lille smule.
Problem 33 - Ja?
>> [Daniel] Jeg har lige haft et hurtigt spørgsmål. Denne stjerne, eller stjernen,
det hedder dereferere, når du bruger en stjerne før.
Hvad kaldes det, når du bruger tegnet før?
>> Tegnet før er adressen-of operatør.
Så lad os rulle tilbage op.
Ups. Jeg er i zoom-mode, så jeg kan ikke rigtig rulle.
Hvis vi ser på denne kode virkelig hurtigt lige her,
igen, samme ting sker.
Hvis vi ser på denne kode lige her, på denne linje, hvor vi foretager opkaldet til at bytte,
tegnet er bare at sige "få den adresse, hvor variable x liv."
Når din compiler kompilerer din kode,
det skal rent fysisk afmærke en plads i hukommelsen for alle dine variabler til at leve.
Og hvad så compileren kan så gøre når den er kompileret alt,
det ved, "Åh, jeg sætter x på adressen 10. Jeg sætter y på adressen 14."
Det kan derefter udfylde disse værdier for dig.
Så du kan da - det kan så videregive denne i og pass & y i så godt.
Disse fyre få adressen, men de har også, når du passerer dem i swap-funktion,
denne type information, denne int * lige her, fortæller compileren,
"Okay, vi kommer til at fortolke denne adresse som en adresse på en heltalsvariabel."
Som en adresse på en int, er der forskellig fra adressen på et tegn variabel
fordi en int optager, på en 32-bit maskine, fylder 4 bytes af rummet,
hvorimod en karakter tager kun op 1 byte plads.
Så det er vigtigt at vide, også hvad der er - hvad bor, hvilken type værdi
bor på den adresse, der fik gået i.
Eller den adresse, du har at gøre med.
På den måde ved du, hvor mange bytes af information til rent faktisk at indlæse ud af din RAM.
Og så, ja, blev denne dereference operatør, ligesom du spørger,
går og adgang til oplysninger på en bestemt adresse.
Så den står, med en variabel her, behandle indholdet af en som en adresse,
gå til denne adresse, og trække ud, indlæse i processoren, belastning i et register
de faktiske værdier eller indholdet, der lever på denne adresse.
Flere spørgsmål? Det er gode spørgsmål.
Det er en masse ny terminologi også.
Det er også lidt funky, ser & og * i forskellige steder.
>> Ok.
Så tilbage til problem 33, fil I / O.
Dette var et af de problemer, som jeg tror et par ting der skete.
En, det er en temmelig nyt emne.
Det blev fremlagt meget snart før quiz,
og så tror jeg, det var lidt ligesom en af ​​disse ord problemer i matematik
hvor de giver dig en masse oplysninger, men du faktisk ikke ender med at skulle bruge et ton af det.
Den første del af dette problem er at beskrive, hvad en CSV-fil er.
Nu, en CSV-fil, ifølge beskrivelsen, er en kommasepareret værdier fil.
Grunden til disse overhovedet er interessante, og grunden til at du nogensinde bruge dem,
er, fordi, hvor mange af jer nogensinde brugt ting som Excel?
Figur fleste af jer har, sandsynligvis, vil eller bruge på et tidspunkt i dit liv.
Du skal bruge noget som Excel.
For at få de data ud af et Excel-regneark eller gøre nogen form for behandling med det,
hvis du ønsker at skrive et C-program eller Python program, Java-program,
at beskæftige sig med de data, du har gemt derinde,
en af ​​de mest almindelige måder at få det ud er i en CSV-fil.
Og du kan åbne op Excel og når du gå til 'Gem som' dialog,
du kan få en egentlig CSV-fil.
>> Handy til at vide, hvordan man skal håndtere disse ting.
Den måde det virker er, at det ligner - jeg mener, det er væsentligt at efterligne et regneark,
når der, som vi ser her, i den meget venstre-mest stykke,
vi har alle de sidste navne.
Så vi har Malan, så Hardison, og derefter Bowden, MacWilliam, og derefter Chan.
Alle de sidste navne. Og så et komma adskiller de sidste navne fra de første navne.
David, Nate, Rob, Tommy, og Zamyla.
Jeg har altid blande Robby og Tom.
Og så, endelig, den tredje kolonne er e-mail adresser.
Når du forstår det, resten af ​​programmet er forholdsvis ligetil at gennemføre.
Hvad vi har gjort, for at efterligne dette samme struktur i vores C-program
er vi har brugt en struktur.
Vi begynder at spille med disse lidt mere så godt.
Vi så dem for første lidt i problemer sæt 3, da vi beskæftiger sig med ordbøger.
Men dette personale struct gemmer et efternavn, et fornavn, og en e-mail.
Ligesom vores CSV fil blev lagring.
Så dette er blot konvertere fra et format til et andet.
Vi er nødt til at konvertere, i dette tilfælde, en ansat struct i en linje,
en kommasepareret linje, ligesom det.
Giver det mening? I gutter har alle taget quizzen,
så jeg forestille mig, du har i det mindste haft lidt tid til at tænke over dette.
>> I leje-funktionen, spørger problem for os at tage på - we'll zoome ind på dette en lille smule -
tage i en personale struktur, et personale struct, med navn s,
og tilføje indholdet til vores staff.csv fil.
Det viser sig, at dette er forholdsvis ligetil at bruge.
Vi slags lege med disse funktioner lidt mere i dag.
Men i dette tilfælde, er det fprintf funktion virkelig nøglen.
Så med fprintf, kan vi udskrive, ligesom jer har brugt printf hele denne valgperiode.
Man kan printf en linje til en fil.
Så i stedet for bare at gøre den sædvanlige printf opkald, hvor du give det format string
og så skal du erstatte alle de variabler med følgende argumenter,
med fprintf, er din allerførste argument i stedet den fil, du vil skrive til.
Hvis vi skulle til at se på dette i apparatet, for eksempel, mand fprintf,
kan vi se forskellen mellem printf og fprintf.
Jeg zoome ind her en lille smule.
Så med printf, giver vi det et format streng, og derefter de efterfølgende argumenter
er alle de variabler for udskiftning eller substitution ind i vores formatstreng.
Betragtninger med fprintf, er det første argument faktisk denne fil * kaldes en strøm.
>> Flytning tilbage herovre til vores leje,
Vi har allerede fået vores fil * stream åbnet for os.
Det er, hvad denne første linje gør, det åbner staff.csv filen,
den åbner det i append mode, og alle, der er tilbage for os at gøre, er
skriver personalet struktur til filen.
Og, lad os se, jeg ønsker at bruge iPad?
Jeg vil bruge iPad. Vi har ugyldige - lad os sætte dette på bordet, så jeg kan skrive lidt bedre -
ugyldig leje og det tager i ét argument, et personale struktur, der kaldes s.
Fik vores seler, har vi fået vores fil * kaldet fil,
vi har vores fopen linje givet os,
og jeg vil bare skrive det som prikker da det er allerede i pedia.
Og så på vores næste linje, vi kommer til at foretage et opkald til fprintf
og vi kommer til at passere i den fil, vi ønsker at udskrive til,
og derefter vores formatstreng, som -
Jeg vil lade jer fortælle mig, hvad det ligner.
Hvad med dig,? Stella Ved du, hvad den første del af formatstreng ser ud?
[Stella] Jeg er ikke sikker. >> Du er velkommen til at spørge Jimmy.
Kender du, Jimmy?
[Jimmy] Vil det bare være sidst? Det ved jeg ikke. Jeg er ikke helt sikker.
>> Okay. Hvad med, har nogen få dette korrekt på eksamen?
Nej Okay.
Det viser sig, at her alt, hvad vi skal gøre, er at vi ønsker hver del af vores personale struktur
skal printes ud som en streng ind i vores fil.
Vi bare bruge strengen substitution karakter tre forskellige tidspunkter, fordi vi har et efternavn
efterfulgt af komma, og derefter et fornavn efterfulgt af et komma,
og så endelig den e-mailadresse, der er fulgt - hvilket ikke er
montering på min skærm - men det er efterfulgt af en ny linje.
Så jeg har tænkt mig at skrive det bare dernede.
Og så efter vores formatstreng,
vi bare have de substitutioner, som vi har adgang til via den dot-notationen
at vi så i problemet sæt 3.
Vi kan bruge s.last, s.first, og s.email
at erstatte i de tre værdier til vores formatstreng.
Så hvordan gik det? Give mening?
Ja? Nej? Muligvis? Okay.
>> Den sidste ting, som vi gør, når vi har udskrevet, og efter vi har åbnet vores fil:
når vi har åbnet en fil, vi altid skal huske at lukke den.
Fordi vi ellers vil ende op lækker hukommelsen,
bruger op fildeskriptorer.
Så for at lukke det, hvilken funktion bruger vi? Daniel?
[Daniel] fclose? >> Fclose, præcis.
Så den sidste del af dette problem var at korrekt lukke filen ved hjælp af fclose funktion,
der bare ligner det.
Ikke vanvittigt.
Cool.
Så det er problem 33 på quizzen.
Vi vil have absolut mere fil I / O kommer op.
Vi vil gøre en lille smule mere i foredrag i dag, eller i snit i dag,
fordi det er hvad der kommer til at danne det meste af denne kommende Pset.
Lad os gå videre fra quizzen på dette punkt. Ja?
>> [Charlotte]] Hvorfor fclose (fil) i stedet for fclose (staff.csv)?
>> Ah. Fordi det viser sig, at - så spørgsmålet, hvilket er en stor en,
er grunden til, når vi skriver fclose, er vi skriver fclose (fil) stjerne variabel
i modsætning til filnavnet, staff.csv? Er det korrekt? Yeah.
Så lad os tage et kig. Hvis jeg skifter tilbage til min laptop,
og lad os se på det fclose funktion.
Så det fclose funktion lukker en stream, og det tager i markøren til den strøm, vi ønsker at lukke,
i modsætning til den aktuelle filnavn, som vi ønsker at lukke.
Og det er fordi bag kulisserne, når du foretager et opkald til fopen,
når du åbner en fil, du faktisk tildele hukommelse til at gemme oplysninger om filen.
Så du har fil pointer, der har oplysninger om filen,
såsom det er åbent, dens størrelse, hvor du er i øjeblikket i filen,
så du kan gøre læsning og skrivning opkald til det pågældende sted i filen.
Du ender lukke pointer i stedet for at lukke filnavnet.
>> Ja? [Daniel] Så for at bruge leje, vil du sige - hvordan kan det få brugeren input?
Har fprintf handle som GetString i den forstand, at det bare vil vente på input fra brugeren
og beder dig om at skrive dette - eller vente for dig at skrive disse tre ting i?
Eller har du brug for at bruge noget til at gennemføre leje?
>> Yeah. Så vi er ikke - spørgsmålet var, hvordan vi får input fra brugeren
for at gennemføre leje? Og hvad vi har her, er den, der ringer til leje,
vedtaget i denne personale struct med alle de data, der er lagret i struct allerede.
Så fprintf er i stand til bare skrive disse data direkte til filen.
Der er ingen ventetid for bruger input.
Brugeren har allerede givet input ved korrekt at sætte det i dette personale struct.
Og ting, selvfølgelig, bryde ville, hvis nogen af ​​disse pointers var null,
så vi rulle tilbage op her, og vi ser på vores struct.
Vi har string sidste, string første streng email.
Vi ved nu, at alle dem virkelig, under kølerhjelmen, er char * variable.
Det kan eller ikke kan pege på null.
De kan pege på hukommelse på heapen,
måske hukommelse på stakken.
Vi ved ikke rigtig, men hvis nogen af ​​disse henvisninger er null, eller ugyldigt,
at der vil helt sikkert gå ned vores leje funktion.
Det var noget, der var lidt uden for rammerne af eksamen.
Vi er ikke bekymre sig om det.
Great. Okay. Så vi går videre fra quizzen.
>> Lad os lukke denne fyr, og vi vil se på Pset 4.
Så hvis du fyre ser på Pset spec, når du kan få adgang til det, cs50.net/quizzes,
vi vil gå igennem et par af afsnittet problemer i dag.
Jeg rulle ned - afsnit med spørgsmål begynder på den tredje side af Pset spec.
Og den første del beder dig om at gå og se kort på omdirigere og rør.
Hvilket var lidt af en kølig kort, viser dig nogle nye, seje kommandolinjeflag tricks som du kan bruge.
Og så har vi fået et par spørgsmål til dig så godt.
Denne første spørgsmål om vandløb, som printf skriver som standard,
vi slags inde på bare en lille smule for et øjeblik siden.
Denne fprintf at vi bare diskuterede tager i en fil * strøm som argument.
fclose tager i en fil * strøm så godt,
og returværdien af ​​fopen giver dig en fil * strøm så godt.
Grunden til at vi ikke har set dem før, når vi har behandlet printf
er fordi printf har en standard stream.
Og den standard strøm, som den skriver
du vil finde ud af om der på kort.
Så helt sikkert tage et kig på det.
>> I dagens afsnit vil vi snakke lidt om GDB,
eftersom den mere velkendte du er med det, jo mere praksis, du får med det,
det bedre i stand du vil være rent faktisk at jagte fejl i din egen kode.
Det fremskynder processen med debugging op voldsomt.
Så ved hjælp af printf, hver gang du gør, at du er nødt til at kompilere din kode,
du er nødt til at køre det igen, nogle gange er du nødt til at flytte printf opkald rundt,
udkommentere kode, det bare tager et stykke tid.
Vores mål er at forsøge at overbevise dig om, at med GDB, kan du hovedsageligt
printf noget på noget tidspunkt i din kode, og du aldrig behøver at kompilere det.
Du behøver aldrig at starte og holde gætte hvor skal printf næste.
Den første ting at gøre, er at kopiere denne linje og få afsnitskendetegnet ud af banen.
Jeg kopiere denne linje kode, der siger, "wget ​​http://cdn.cs50.net".
Jeg har tænkt mig at kopiere den.
Jeg har tænkt mig at gå over til min apparat, zoome ud, så du kan se, hvad jeg gør,
indsætte det i der, og når jeg trykker på Enter, denne wget kommando bogstaveligt er et web får.
Det kommer til at trække ned denne fil ud af internettet,
og det kommer til at gemme den til den aktuelle mappe.
Nu hvis jeg liste min nuværende bibliotek kan du se, at jeg har fået denne section5.zip fil derinde.
Den måde at beskæftige sig med den fyr, er at pakke den,
som du kan gøre i kommandolinjen, ligesom dette.
Section5.zip.
Det vil unzip det, skal du oprette mappen for mig,
oppuste hele indholdet, sætte dem derinde.
Så nu kan jeg gå ind i mit afsnit 5 mappe ved hjælp af kommandoen cd.
Ryd skærmen med tydelig. Så rydde skærmen.
Nu har jeg fået en dejlig ren terminal at beskæftige sig med.
>> Nu, hvis jeg en liste over alle de filer, som jeg ser i denne mappe,
du se, at jeg har fire filer: buggy1, buggy2, buggy3 og buggy4.
Jeg har også fået deres tilsvarende. C-filer.
Vi kommer ikke til at se på de. C-filer for nu.
I stedet vil vi bruge dem, når vi åbner op GDB.
Vi har holdt dem rundt, så vi har adgang til den egentlige kilde kode, når vi bruger GDB,
men målet for denne del af afsnittet er at pille rundt med GDB
og se, hvordan vi kan bruge det til at finde ud af, hvad der går galt med hver af disse fire buggy programmer.
Så vi vil bare rundt i lokalet virkelig hurtigt,
og jeg har tænkt mig at spørge nogen til at køre en af ​​de buggy programmer,
og så vil vi gå som en gruppe gennem GDB, og vi vil se hvad vi kan gøre for at løse disse programmer,
eller i det mindste identificere, hvad der går galt i hver af dem.
Lad os starte forfra her med Daniel. Vil du køre buggy1? Lad os se hvad der sker.
[Daniel] Det siger, at der er et program fejl. >> Yeah. Præcis.
Så hvis jeg løber buggy1, får jeg en seg fejl.
På dette tidspunkt kunne jeg gå og åbne op buggy1.c,
forsøge at finde ud af, hvad der går galt,
men en af ​​de mest ubehagelige ting om dette seg fejl fejl
er, at det ikke fortæller dig om, hvad linje af programmets tingene faktisk gik galt og brød.
Du slags nødt til at se på koden
og finde ud af ved hjælp af gæt og tjek eller printf for at se, hvad der går galt.
En af de fedeste ting ved GDB er, at det er virkelig, virkelig nemt
at finde ud af den linje, hvor dit program går ned.
Det er fuldstændig det værd at bruge det, selv om bare for det.
Så til at starte op GDB, jeg skriver GDB, og så giver jeg det stien til den eksekverbare, at jeg vil køre.
Her Jeg skriver gdb ./buggy1.
Hit på Enter. Giver mig alt dette oplysninger om ophavsret,
og hernede du vil se denne linje, der siger, "Reading symboler fra / home /
jharvard/section5/buggy1. "
Og hvis alt går vel, vil du se det udskrive en besked, der ligner denne.
Det vil læse symboler, vil det sige "Jeg læser symboler fra din eksekverbar fil,"
og så vil det have denne "done" budskab herovre.
Hvis du ser en anden variation af dette, eller du kan se kan det ikke finde symbolerne
eller noget lignende, hvad det betyder er, at du bare ikke har kompileret din eksekverbare ordentligt.
Når vi udarbejder programmer til brug med GDB, er vi nødt til at bruge den særlige g flag,
og det er gjort som standard, hvis du kompilere dine programmer, blot ved at skrive make
eller gøre buggy eller gøre inddrive, nogen af ​​dem.
Men hvis du kompilere manuelt med Dunk, så du bliver nødt til at gå ind og omfatte, at-g flag.
>> På dette tidspunkt, at vi nu har vores GDB prompt,
det er ret simpelt at køre programmet.
Vi kan enten skrive løb, eller vi kan blot skrive r.
De fleste GDB kommandoer kan forkortes.
Normalt til blot en eller et par bogstaver, som er temmelig nice.
Så Saad, hvis du skriver r og tryk på Enter, hvad sker der?
[Saad] Jeg fik SIGSEGV, segmentering fejl og derefter alt dette volapyk.
>> Yeah.
Ligesom vi ser på skærmen lige nu, og ligesom Saad sagde,
når vi skriver run eller r og tryk på Enter, vi stadig få den samme seg skyld.
Så ved hjælp GDB løser ikke vores problem.
Men det giver os nogle volapyk, og det viser sig, at denne volapyk
faktisk fortæller os, hvor det sker.
At parse dette en lille smule, denne første bit er den funktion, hvor alting går galt.
Der er denne __ strcmp_sse4_2, og det fortæller os, at det sker i denne fil
kaldet sysdeps/i386, alt dette igen, sådan et rod - men linie 254.
Det er lidt svært at parse. Normalt når du ser ting som dette,
det betyder, at det er seg forkastning i en af ​​systembiblioteker.
Så noget at gøre med strcmp. I gutter har set strcmp før.
Ikke vanvittigt, men betyder det, at strcmp er brudt, eller at der er et problem med strcmp?
Hvad tror du, Alexander?
[Alexander] Er det - er 254 linjen? Og - ikke den binære, men det er ikke deres lofter,
og så er der et andet sprog for hver funktion. Er det 254 i denne funktion, eller -?
>> Det er linie 254. Det ligner i denne. Sagsakter, så det er forsamling kode sandsynligvis.
>> Men jeg gætter på mere presserende ting er, fordi vi har fået en seg fejl,
og det ser ud som det kommer fra den strcmp funktion,
indebærer dette, så er det strcmp brudt?
Det skal ikke, forhåbentlig. Så bare fordi du har en segmenteringsfejl
i en af ​​systemets funktioner, betyder typisk, at du netop ikke har kaldt det korrekt.
Den hurtigste ting at gøre for at finde ud af, hvad der rent faktisk sker
når du ser noget vanvittigt som dette, hver gang du ser en seg fejl,
især hvis du har et program, der bruger mere end bare main,
er at bruge en backtrace.
I forkorte backtrace ved at skrive bt, i modsætning til den fulde backtrace ord.
Men Charlotte, hvad der sker, når du skriver bt og tryk på Enter?
[Charlotte] Det viser mig to linjer, linje 0 og linie 1.
>> Yeah. Så linje 0 og linie 1.
Det er de faktiske stakrammer, der var i øjeblikket i spil, når dit program styrtede ned.
Begyndende fra den øverste ramme, ramme 0, og gå til den nederste, som er rammen 1.
Vores øverste ramme er det strcmp ramme.
Du kan tænke på det som svarer til det problem vi blot gør på quiz med pegepinde,
hvor vi havde swap stakramme på toppen af ​​main stakramme,
og vi havde de variabler, som swap brugte på toppen af ​​de variabler, main var bruger.
Her vores styrt skete i vores strcmp funktion, der blev kaldt af vores vigtigste funktion,
og backtrace giver os ikke kun de funktioner, som tingene mislykkedes,
men det er også fortæller os, hvor alt blev kaldt fra.
Så hvis jeg ruller over et lidt mere til højre,
Vi kan se, at ja, vi var på linje 254 i denne strcmp-sse4.s fil.
Men opkaldet blev foretaget ved buggy1.c, linie 6.
Så det betyder, at vi kan gøre - er at vi bare kan gå tjekke ud og se, hvad der foregik
ved buggy1.c, linie 6.
Igen er der et par måder at gøre dette. Den ene er at afslutte ud af GDB
eller få din kode åbner i et andet vindue og krydsreference.
Det er i og for sig selv, er temmelig praktisk, fordi nu, hvis du er i kontortiden
og du har fået en seg fejl og din TF er gad vide hvor alting var ved at bryde,
kan du bare sige: "Åh, linje 6. Jeg ved ikke, hvad der foregår,
men noget om linje 6 forårsager mit program til at bryde. "
Den anden måde at gøre det er, kan du bruge denne kommando kaldet liste i GDB.
Du kan også forkorte den med l..
Så hvis vi rammer l, hvad vi får her?
Vi får en hel masse underlige ting.
Dette er den faktiske samling kode
der er i strcmp_sse4_2.
Det ser lidt funky,
og grunden til at vi får det er fordi lige nu,
GDB har os i ramme 0.
>> Så når som helst vi ser på variabler, hver gang vi ser på kildekoden
vi kigger på kildekoden, der relaterer til stakrammen vi er i øjeblikket i.
Så for at få noget meningsfuldt, er vi nødt til
flytte til en stak ramme, der giver mere mening.
I dette tilfælde ville den vigtigste stakramme gøre lidt mere mening,
fordi det var faktisk den kode, vi skrev.
Ikke den strcmp kode.
Den måde, du kan flytte mellem rammer, i dette tilfælde, fordi vi har to,
Vi har 0 og 1,
du gøre det med op-og ned-kommandoer.
Hvis jeg flytter op én ramme,
nu er jeg i den vigtigste stakramme.
Jeg kan flytte ned for at gå tilbage til hvor jeg var,
gå op igen, gå ned igen, og gå op igen.
Hvis du nogensinde gøre dit program i GDB, du får et crash, får du backtrace,
og du kan se, at det er i nogle fil, som du ikke ved, hvad der foregĺr.
Du prøver liste, er koden ikke virke bekendt for dig,
tage et kig på dine rammer og finde ud af hvor du er.
Du er sandsynligvis i den forkerte stakramme.
Eller i det mindste du er i en stak ramme, der er ikke en, som du virkelig kan debug.
Nu, hvor vi er i den rette stakramme, vi er i main,
nu kan vi bruge listen kommandoen til at regne ud, hvad linjen var.
Og du kan se det, det udskrives det for os lige her.
Men vi kan ramme en liste over alle de samme, og listen giver os denne nice udskrift
af den faktiske kildekode, der foregår herinde.
>> I særdeleshed kan vi se på linje 6.
Vi kan se, hvad der foregår her.
Og det ser ud til vi laver en streng sammenligning
mellem strengen "CS50 rocks" og argv [1].
Noget om dette var ned.
Så Missy, har du nogen tanker om, hvad der kunne ske her?
[Missy] Jeg ved ikke, hvorfor det er ned. >> Du ved ikke, hvorfor det er ned?
Jimmy, nogen tanker?
[Jimmy] Jeg er ikke helt sikker, men sidste gang vi brugte streng sammenligne,
eller strcmp, havde vi ligesom tre forskellige tilfælde under det.
Vi havde ikke en ==, tror jeg ikke, ret i, at første linje.
I stedet blev opdelt i tre, og én var == 0,
den ene var <0, tror jeg, og én var> 0.
Så måske noget i den retning? >> Yeah. Så der er dette problem
af gør vi sammenligningen korrekt?
Stella? Nogen tanker?
[Stella] Jeg er ikke sikker. >> Ikke sikker. Daniel? Tanker? Okay.
Det viser sig, hvad der sker lige her er, når vi kørte programmet
og vi fik den seg fejl, da du kørte programmet for første gang, Daniel,
gav du det nogen kommandolinjeargumenter?
[Daniel] Nej >> Nej. I så fald, hvad er værdien af ​​argv [1]?
>> Der er ingen værdi. >> Højre.
Nå, der er nogen hensigtsmæssig streng værdi.
Men der er en vis værdi. Hvad er den værdi, bliver gemt derinde?
>> En skrald værdi? >> Det er enten en skraldespand værdi eller, i dette tilfælde,
enden af ​​argv arrayet altid afsluttet med nul.
Så hvad der rent faktisk fik gemt i der er null.
Den anden måde at løse dette, snarere end at tænke det igennem,
er at prøve at udskrive det.
Det er her, jeg sagde, at bruge GDB er stor,
fordi du kan printe ud alle de variabler, alle de værdier, du vil
ved hjælp af denne handy-dandy p kommando.
Så hvis jeg skriver p og derefter jeg skrive værdien af ​​en variabel eller navnet på en variabel,
sige, argc, jeg kan se, at argc er 1.
Hvis jeg ønsker at udskrive argv [0], kan jeg gøre det ligesom det.
Og som vi så, argv [0] er altid navnet på dit program,
altid navnet på den eksekverbare.
Her kan du se det har fået den fulde sti navn.
Jeg kan også printe ud argv [1] og se hvad der sker.
>> Her fik vi denne slags mystiske værdi.
Vi fik denne 0x0.
Husk ved begyndelsen af ​​udtrykket, når vi talte om hexadecimale tal?
Eller den lille spørgsmål i slutningen af ​​Pset 0 om, hvordan du repræsentere 50 i hex?
Den måde, vi skriver hex numre i CS, bare for ikke at forvirre os selv
med decimaltal, er vi altid præfiks dem med 0x.
Så denne 0x altid betyder blot fortolke følgende nummer som et hexadecimalt tal,
ikke som en streng, ikke som et decimaltal, som ikke er et binært tal.
Da nummer 5-0 er et gyldigt tal i hexadecimal.
Og det er et tal i decimal, 50.
Så det er bare hvordan vi disambiguate.
Så 0x0 midler hexadecimal 0, som også decimal 0, binære 0.
Det er bare værdien 0.
Det viser sig, at det er det nul er, faktisk, i hukommelsen.
Null er blot 0.
Her bestanddelen opbevaret ved argv [1] er nul.
Så vi prøver at sammenligne vores "CS50 rocks" streng til en null-streng.
Så dereferere null, forsøger at få adgang ting på null,
de er typisk vil forårsage en slags segmentering fejl eller andre dårlige ting til at ske.
Og det viser sig, at strcmp ikke kontrollerer at se
uanset om du har bestået i en værdi, der er null.
Snarere er det bare går fremad, forsøger at gøre sin ting,
og hvis det seg fejl, det seg fejl, og det er dit problem. Du skal gå løse det.
Virkelig hurtigt, hvordan kunne vi løse dette problem? Charlotte?
[Charlotte] Du kan tjekke med hvis.
Så hvis argv [1] er null, == 0, derefter returnere 1, eller noget [uforståeligt].
>> Yeah. Så det er en god måde at gøre det, som vi kan kontrollere at se,
den værdi, vi er ved at passere ind strcmp, argv [1], er det null?
Hvis det er null, så kan vi sige okay, afbryde.
>> En mere almindelig måde at gøre dette på er at bruge den argc værdi.
Du kan se lige her i starten af ​​main,
vi udeladt den første test, som vi typisk gør, når vi bruger kommandolinjeargumenter,
som er at teste, hvorvidt vores argc værdi er, hvad vi forventer.
I dette tilfælde er vi forventer mindst to argumenter,
navnet på programmet plus en anden.
Fordi vi er ved at bruge det andet argument lige her.
Så har en slags test på forhånd, før vores strcmp opkald
at prøverne eller ej argv er mindst 2, vil også gøre det samme slags ting.
Vi kan se, om det virker ved at køre programmet igen.
Du kan altid genstarte din program inden GDB, som er virkelig rart.
Du kan køre, og når du passerer på argumenter til dit program,
du passerer dem i, når du ringer kører, ikke når du starter op GDB.
På den måde kan du holde påberåbe dit program med forskellige argumenter hver gang.
Så køre, eller igen, kan jeg skrive r, og lad os se hvad der sker, hvis vi skriver "hej".
Det vil altid spørge dig, om du ønsker at starte det fra begyndelsen igen.
Normalt vil du starte det fra begyndelsen igen.
Og på dette punkt, det genstarter den igen, den udskriver
det program, vi kører, buggy1, med det argument hej,
og den udskriver denne standard ud, den siger, "Du får en D," trist ansigt.
Men vi havde ikke seg fejl. Det siges, at processen afsluttet normalt.
Så det ser godt ud.
Ikke mere seg fejl, vi gjorde det forbi,
så det ligner det faktisk var seg fejl bug, som vi fik.
Desværre, det fortæller os, at vi får et D.
>> Vi kan gå tilbage og se på koden og se, hvad der foregik der
at finde ud af, hvad der var - hvorfor det fortalte os, at vi fik et D.
Lad os se, her var det printf at sige, at du fik en D.
Hvis vi skriver liste, som du holder skrive liste, det holder iteration ned gennem dit program,
så det vil vise dig de første par linjer af dit program.
Så det vil vise dig de næste par linjer, og den næste luns og den næste bid.
Og det vil holde forsøger at gå ned.
Og nu får vi at "Line nummer 16 er uden for rækkevidde."
Fordi det kun har 15 linjer.
Hvis du kommer til dette punkt, og din undrende, "Hvad skal jeg gøre?" kan du bruge kommandoen help.
Brug hjælp og derefter give det navnet på en kommando.
Og du kan se GDB giver os alle den slags ting.
Det siger, "Med noget argument, opregner yderligere ti linjer efter eller omkring den tidligere fortegnelse.
List - en liste over de ti linjer før - "
Så lad os prøve at bruge liste minus.
Og det viser de 10 linier tidligere, og du kan lege med liste en lille smule.
Du kan gøre listen, liste - du kan endda give en liste over et nummer, ligesom liste 8,
og det vil en liste over de 10 linier omkring linie 8.
Og du kan se, hvad der foregår her, er at du har en enkel, hvis andet.
Hvis du skriver i CS50 klipper, den udskriver "Du får et A."
Ellers udskriver "Du får en D."
Nedern by. Ok. Ja?
>> [Daniel] Så når jeg forsøgte at gøre CS50 klipper uden anførselstegn,
det siger "Du får en D."
Jeg havde brug for citater for at få det til at virke, hvorfor så det?
>> Yeah. Det viser sig, at når - det er en anden sjov lille tidbit -
når du kører programmet, hvis vi kører det, og vi skriver i CS50 klipper,
ligesom Daniel sagde han gjorde, og du trykker på Enter,
det stadig siger vi får en D.
Og spørgsmålet er, hvorfor er dette?
Og det viser sig, at både vores terminal og GDB parse disse som to separate argumenter.
For når der er en plads, der er underforstået som
det første argument ophørt den næste argument er ved at begynde.
Den måde at kombinere dem i to, eller ked af det, i ét argument,
er at bruge citater.
Så nu, hvis vi sætter det i anførselstegn og køre det igen, får vi et A.
Så bare for at opsummere, ingen citater, CS50 og klipper parses som to separate argumenter.
Med citater, er det parses som ét argument helt.
>> Vi kan se dette med et breakpoint.
Indtil videre har vi kørt vores program, og det er kørt
indtil enten det seg fejl eller hits en fejl
eller indtil det har forladt, og alle har været helt fint.
Dette er ikke nødvendigvis den mest nyttige ting, fordi nogle gange
du har en fejl i dit program, men det er ikke forårsager en segmentering fejl.
Det er ikke forårsager din program til at stoppe eller sådan noget.
Den måde at få GDB til pause dit program på et bestemt punkt
er at sætte et breakpoint.
Du kan enten gøre dette ved at sætte et breakpoint på et funktionsnavn
eller du kan indstille en breakpoint på en bestemt linje kode.
Jeg kan godt lide at sætte breakpoints på funktion navne, fordi - let at huske,
og hvis du rent faktisk gå ind og ændre din kildekode op en lille smule,
så vil din breakpoint vil faktisk bo på det samme sted i din kode.
Hvorimod hvis du bruger linjenumre, og linjenumrene ændrer
fordi du tilføjer eller sletter noget kode, så dine breakpoints er alle helt skruet op.
En af de mest almindelige ting, jeg gør er sat en breakpoint på den primære funktion.
Ofte vil jeg starte op GDB, vil jeg skrive b main, tryk på Enter, og der vil sætte en breakpoint
på den vigtigste funktion, som bare siger, "pause i programmet, så snart du begynder at køre,"
og på den måde, når jeg kører mit program med, siger, CS50 klipper som to argumenter
og tryk Enter, det bliver til hovedfunktionen, og det stopper lige ved den allerførste linje,
lige før det vurderer den strcmp funktion.
>> Da jeg er sat på pause, nu kan jeg begynde mucking rundt og se, hvad der foregår
med alle de forskellige variabler, der er gået ind i mit program.
Her kan jeg printe ud argc og se, hvad der foregår.
Se, at argc er 3, fordi det har fået 3 forskellige værdier i det.
Det har fået navnet på det program, har det fået det første argument, og det andet argument.
Vi kan printe dem ud ved at kigge på argv [0], argv [1], og argv [2].
Så nu kan du også se, hvorfor dette strcmp opkald kommer til at mislykkes,
fordi du kan se, at det gjorde opsplitte CS50 og klipperne i to separate argumenter.
På dette punkt, når du har ramt et breakpoint kan du fortsætte med at springe gennem Deres program
linje for linje, i modsætning til at starte programmet igen.
Så hvis du ikke ønsker at starte programmet igen og bare fortsætte herfra,
du kan bruge continue kommando og fortsætter vil køre programmet til ende.
Ligesom det gjorde her.
Men hvis jeg genstarte programmet, CS50 klipper, det rammer min breakpoint igen,
og denne gang, hvis jeg ikke ønsker at bare gå hele vejen gennem resten af ​​programmet,
Jeg kan bruge den næste kommando, som jeg også forkorte med n.
Og det vil gå gennem programmet linje for linje.
Så du kan se som tingene udføre, som variable forandring, som tingene bliver opdateret.
Hvilket er temmelig nice.
Den anden cool ting er stedet for at gentage den samme kommando igen og igen og igen,
hvis du bare trykke Enter - så her kan du se, jeg har ikke skrevet i noget -
hvis jeg bare trykke Enter, vil det gentage den forrige kommando,
eller den forrige GDB kommando, som jeg lige har lagt i.
Jeg kan holde trykke Enter og det vil holde trinvist gennem min kode linje for linje.
Jeg vil opfordre jer til at gå tjekke de andre buggy programmer også.
Vi har ikke tid til at komme igennem dem alle i dag i snit.
Kildekoden er der, så du kan slags se, hvad der foregår
bag kulisserne, hvis du virkelig sidder fast,
men i det mindste, øve bare starter op GDB,
køre programmet indtil den bryder på dig,
få backtrace, finde ud af hvad fungere flystyrtet var i,
hvilken linje det var på, udskrivning ud nogle variable værdier,
bare så du får en fornemmelse for det, fordi der virkelig vil hjælpe dig fremover.
På dette tidspunkt vil vi holde op ud af GDB, som du bruger afslutte eller bare q.
Hvis dit program er midt i at køre endnu, og det har ikke forladt,
det vil altid spørge dig, "Er du sikker på at du virkelig ønsker at holde op?"
Du kan bare trykke ja.
>> Nu vil vi se på det næste problem, vi har, som er katten program.
Hvis du ser kort på omdirigere og rør, vil du se, at Tommy bruger dette program
der dybest set udskriver alle resultater af en fil til skærmen.
Så hvis jeg løber kat, det er faktisk en indbygget program til apparatet,
og hvis du har Mac-computere, du kan gøre dette på din Mac også, hvis du åbner terminal.
Og vi - kat, lad os sige, cp.c, og tryk på Enter.
Hvad dette gjorde, hvis vi rulle op en lille smule og se, hvor vi kørte linjen,
eller hvor vi kørte katten kommando, det bogstavelig talt lige udskrives indholdet af cp.c til vores skærm.
Vi kan køre det igen, og du kan sætte i flere filer sammen.
Så du kan gøre katten cp.c, og så kan vi også sammenkæde den cat.c fil,
som er det program, vi er ved at skrive,
og det vil udskrive begge filer tilbage til tilbage til vores skærm.
Så hvis vi rulle op en lille smule, kan vi se, at når vi kørte denne kat cp.c, cat.c,
Først udskrives den cp-filen, og derefter under det, printet det ud den cat.c fil lige hernede.
Vi vil bruge dette til bare få vores våde fødder.
Leg med almindelig udskrivning til terminalen, se, hvordan det virker.
Hvis du fyre åbner med gedit cat.c, tryk Enter,
du kan se det program, vi er ved at skrive.
Vi har medtaget denne nice kedel plade, så vi ikke behøver at bruge tid på at skrive alt det ud.
Vi tjekker også antallet af argumenter gik i.
Vi udskriver en dejlig brugsmeddelelse.
>> Det er den slags ting, der, igen, ligesom vi har talt om,
det er næsten ligesom muskel hukommelse.
Bare husk at holde gør det samme slags ting
og altid udskrive en slags nyttige besked
, så folk ved, hvordan du kører dit program.
Med kat, er det ret simpelt, vi bare kommer til at gå igennem alle de forskellige argumenter
der blev overført til vores program, og vi vil udskrive
deres indhold ud til skærmen en ad gangen.
For at udskrive filer ud til skærmen, vi kommer til at gøre noget meget lignende
til, hvad vi gjorde i slutningen af ​​quizzen.
I slutningen af ​​quizzen, der ansætter program, måtte vi åbne op for en fil,
og derefter havde vi at udskrive til den.
I dette tilfælde vil vi åbne en fil, og vi vil læse fra det i stedet.
Så vi kommer til at udskrive, i stedet for til en fil, vi kommer til at udskrive til skærmen.
Så udskriver til skærmen, du har alle gjort før med printf.
Så det er ikke vanvittigt.
Men læser en fil er lidt underligt.
Vi vil gå igennem det en lille smule ad gangen.
Hvis du fyre gå tilbage til det sidste problem på din quiz, problem 33,
den første linje, at vi vil gøre her, at åbne filen, er meget lig hvad vi gjorde der.
Så Stella, hvad betyder denne linje se ud, når vi åbner en fil?
[Stella] Capital FIL *, fil - >> Okay. >> - Er lig med fopen. >> Yup.
Som i dette tilfælde er? Det er i kommentaren.
>> Det er i kommentaren? argv [i] og r?
>> Præcis. Lige på. Så Stella er helt rigtigt.
Dette er, hvad den linje ser ud.
Vi kommer til at få en fil stream variabel, skal det opbevares i en fil *, så alle caps,
FILE, *, og navnet på denne variabel vil være fil.
Vi kunne kalde det hvad vi vil. Vi kunne kalde det first_file, eller file_i, hvad vi gerne vil.
Og derefter navnet på filen blev vedtaget i på kommandolinjen til dette program.
Så det er gemt i argv [i,] og derefter vil vi åbne denne fil i læse mode.
Nu da vi har åbnet filen, hvad er de ting, vi altid skal huske at gøre
når vi har åbnet en fil? Luk den.
Så Missy, hvordan vi lukker en fil?
[Missy] fclose (fil) >> fclose (fil). Præcis.
Great. Okay. Hvis vi ser på dette at gøre kommentar lige her,
den siger, "Open argv [i] og udskrive dens indhold til stdout."
>> Standard ud er et underligt navn. Stdout er bare vores måde at sige
vi ønsker at printe det til terminalen, vi ønsker at printe det til standard output stream.
Vi kan faktisk slippe af med denne kommentar lige her.
Jeg har tænkt mig at kopiere og indsætte det, da det er, hvad vi gjorde.
På dette tidspunkt, har vi nu til at læse filen lidt efter lidt.
Vi har diskuteret et par måder at læse filer.
Hvilke af dem er din favorit indtil videre?
Hvilke måder har du set eller kan du huske, at læse filer?
[Daniel] fread? >> Fread? Så fread er én. Jimmy, kender du nogen andre?
[Jimmy] Nej >> Okay. Nope. Charlotte? Alexander? Eventuelle andre? Okay.
Så de andre er fgetc, er en, som vi vil bruge en masse.
Der er også fscanf, du fyre se et mønster her?
De har alle begynder med f. Noget at gøre med en fil.
Der er fread, fgetc, fscanf. Disse er alle de læsning funktioner.
For at skrive vi har fwrite, har vi fputc stedet for fgetc.
Vi har også fprintf gerne vi så på quizzen.
Da dette er et problem, der involverer læsning fra en fil,
vi kommer til at bruge en af ​​disse tre funktioner.
Vi kommer ikke til at bruge disse funktioner hernede.
Disse funktioner er alle fundet i standard I / O-bibliotek.
Så hvis man ser på toppen af ​​dette program,
du kan se, at vi allerede har inkluderet header filen for standard I / O-bibliotek.
Hvis vi ønsker at finde ud af hvilken en vi vil bruge,
Vi kan altid åbne man-siderne.
Så vi kan skrive mand stdio
og læs alt om stdio input-og output-funktioner i C.
Og vi kan allerede se oh, se. Det nævne fgetc, det nævne fputc.
Så du kan bore ned lidt og se på, siger, fgetc
og se på sin mand siden.
Du kan se, at det går sammen med en hel masse andre funktioner:
fgetc, fgets, getc, getchar, får, ungetc, og dens input af tegn og strygere.
Så det er sådan vi læser i tegn og strygere fra filer fra standard input,
som i det væsentlige fra brugeren.
Og det er, hvordan vi gør det i virkeligheden C.
Så dette er ikke bruger GetString og getchar funktioner
at vi anvendt fra CS50 biblioteket.
Vi vil gøre dette problem i et par forskellige måder
så du kan se to forskellige måder at gøre det.
Både fread funktion, Daniel nævnt og fgetc er gode måder at gøre det.
Jeg tror fgetc er lidt nemmere, fordi det kun har, som du ser,
et argument, det FILE *, at vi forsøger at læse karakter fra,
og dens returværdi er en int.
Og det er lidt forvirrende, ikke?
>> Fordi vi får en karakter, så hvorfor ikke dette afkast en char?
I gutter har nogen ideer om, hvorfor dette måske ikke returnere en char?
[Missy svar, uforståelig] >> Yeah. Så Missy er helt rigtigt.
Hvis det er ASCII, så er denne heltal kan kortlægges til en faktisk char.
Kunne være et ASCII-tegn, og det er rigtigt.
Det er præcis, hvad der sker.
Vi bruger en int, blot fordi den har flere bits.
Det er større end en char, vores char kun har 8 bit, at 1 byte på vores 32-bit maskiner.
Og en int har alle 4 bytes 'værd af plads.
Og det viser sig, at den måde fgetc virker,
hvis vi rulle ned i vores synopsis i denne mand side en lille smule,
rulle hele vejen ned. Det viser sig, at de bruger denne særlige værdi kaldet EOF.
Det er en speciel konstant som returværdien af ​​fgetc funktion
hver gang du rammer slutningen af ​​filen, eller hvis du får en fejl.
Og det viser sig, at for at gøre disse sammenligninger med EOF ordentligt,
du vil have den ekstra mængde information, du har i en int
i modsætning til anvendelse af en char variabel.
Selvom fgetc effektivt at få en karakter fra en fil,
du ønsker at huske, at det er på vej tilbage noget, der er af typen int til dig.
Når det er sagt, er det forholdsvis let at bruge.
Det kommer til at give os en karakter, så alle vi skal gøre, er at spørge filen,
"Giv mig det næste tegn, giv mig det næste tegn, giv mig det næste tegn,"
indtil vi kommer til slutningen af ​​filen.
Og det vil trække i ét tegn ad gangen fra vores fil,
og så kan vi gøre, hvad vi vil med det.
Vi kan gemme det, kan vi tilføje det til en streng, vi kan printe det ud.
Gør noget af det.
>> Zoome ud igen og går tilbage til vores cat.c program,
hvis vi skal bruge fgetc,
hvordan kan vi gribe dette næste linje kode?
Vi kommer til at bruge - fread vil gøre noget lidt anderledes.
Og denne gang, vil vi bare bruge fgetc til at få et tegn ad gangen.
For at behandle en hel fil, hvad kan vi så gøre?
Hvor mange karakterer er der i en fil?
Der er mange. Så har du sandsynligvis ønsker at få en
og derefter få en anden og få en anden og få en anden.
Hvilken slags algoritme tror du, vi måske nødt til at bruge her?
Hvilken type -? [Alexander] En for-løkke? >> Præcis.
En form for loop.
En for-løkke er faktisk stor, i dette tilfælde.
Og som du sagde, det lyder som om du vil have en sløjfe over hele filen,
få et tegn ad gangen.
Eventuelle forslag til, hvad der kunne ligne?
[Alexander, uforståelig]
>> Okay, bare fortælle mig på engelsk hvad du prøver at gøre? [Alexander, uforståelig]
Så i dette tilfælde, lyder det som om vi bare forsøger at sløjfe over hele filen.
[Alexander] Så jeg > Størrelsen af ​​-?
Jeg gætte størrelsen af ​​filen, ikke? Størrelsen - we'll bare skrive det sådan her.
Størrelse på filen for tiden, i + +.
Så det viser sig, at den måde, du gør dette ved hjælp af fgetc, og dette er nyt,
er, at der ikke er nogen nem måde at bare få størrelsen på en fil
med denne "sizeof" type konstruere, at du har set før.
Når vi bruger det fgetc funktion, introducerer vi en slags
nye, funky syntaks til dette for-løkke, hvor der i stedet for at bruge bare en grundlæggende tæller
at gå tegn for tegn, vi kommer til at trække et tegn ad gangen,
et tegn ad gangen, og den måde, vi ved, vi er i slutningen
ikke, når vi har talt et bestemt antal tegn,
men når den karakter vi trække sig ud, er, at speciel slutning på fil karakter.
Så vi kan gøre dette ved - jeg kalder denne lm, og vi vil initialisere det
med vores første opkald for at få det første tegn ud af filen.
Så denne del lige her, vil dette få en karakter ud af filen
og gemme den i den variable lm.
Vi kommer til at holde gøre dette, indtil vi kommer til slutningen af ​​filen,
som vi gør ved at teste for den karakter ikke er lig med, at særlige EOF karakter.
Og så i stedet for at gøre lm + +, ville der blot øge værdien,
så hvis vi læser en A ud af filen, en kapital A, siger,
ch + + ville give os b, og så vi ville få c og derefter d.
Det er tydeligvis ikke, hvad vi ønsker. Hvad vi ønsker her
i denne sidste bit er vi ønsker at få det næste tegn fra filen.
>> Så hvordan kan vi få det næste tegn fra filen?
Hvordan får vi det første tegn fra filen?
[Student] fgetfile? >> Fgetc, eller, undskyld, du var helt rigtigt.
Jeg stavede det lige der. Så yeah.
Her stedet for at gøre lm + +,
vi bare vil kalde fgetc (fil) igen
og gemme resultatet i vores samme lm variabel.
[Student spørgsmål, uforståelig]
>> Dette er, hvor disse fil * fyre er speciel.
Den måde, de arbejder, er de - når du først åbne - når du først gør, at fopen opkald,
FILE * reelt fungerer som en pegepind til begyndelsen af ​​filen.
Og så hver gang du ringer fgetc, flyttes et tegn gennem filen.
Så når du kalder det, er du inkrementering filpointeren med ét tegn.
Og når du fgetc igen, er du flytter det en anden karakter
og en anden karakter og anden karakter og et andet tegn.
[Student spørgsmål, uforståelig] >> And that's - yeah.
Det er lidt af denne magi under kølerhjelmen.
Du skal bare holde forøgelsen igennem.
På dette tidspunkt, er du i stand til rent faktisk at arbejde med en karakter.
Så hvordan kan vi udskrive denne ud til skærmen, nu?
Vi kan bruge den samme printf ting, som vi brugte før.
At vi har brugt al semester.
Vi kan kalde printf,
og vi kan passere i karakter ligesom det.
En anden måde at gøre det er snarere end at bruge printf og at skulle gøre dette format streng,
Vi kan også bruge en af ​​de andre funktioner.
Vi kan bruge fputc, som udskriver et tegn til skærmen,
undtagen hvis vi ser på fputc - lad mig zoome ud en lille smule.
Vi ser, hvad der er rart er det tager i det tegn, vi læser ved hjælp fgetc,
men så er vi nødt til at give det en strøm til at udskrive til.
Vi kan også bruge putchar funktion, som vil sætte direkte til standard ud.
Så der er en hel masse forskellige muligheder, som vi kan bruge til udskrivning.
De er alle i standard I / O-bibliotek.
Når du vil udskrive - så printf, som standard, vil udskrive til den særlige standard ud stream,
nemlig at stdout.
Så vi kan bare henvise til det som en slags denne magiske værdi, stdout herinde.
Ups. Sæt semikolon udenfor.
>> Dette er en masse nye, funky information herinde.
Meget af dette er meget idiomatisk, i den forstand at det er kode
der er skrevet på denne måde, bare fordi det er ren at læse, let at læse.
Der er mange forskellige måder at gøre det, mange forskellige funktioner, du kan bruge,
men vi har en tendens til blot følge de samme mønstre igen og igen.
Så du skal ikke blive overrasket, hvis du ser kode som denne kommer op igen og igen.
Ok. På dette tidspunkt er vi nødt til at bryde for dagen.
Tak for at komme. Tak for at se, hvis du er online. Og vi vil se dig næste uge.
[CS50.TV]