[Powered by Google Translate] [DEL 5: mindre komfortable]
[Nate Hardison, Harvard University]
[Dette er CS50.] [CS50.TV]
Så velkommen tilbake, folkens.
Velkommen til § 5.
På dette punktet, etter å ha fullført quiz 0 og etter å ha sett hvordan du har gjort,
forhåpentligvis du føler deg virkelig bra fordi jeg var veldig imponert resultatet i denne delen.
For våre online seere, har vi hatt et par spørsmål
om de to siste problemene på oppgavesettet - eller på quiz, heller.
Så vi kommer til å gå over dem veldig raskt, slik at alle ser hva som skjedde
og hvordan du skal gå gjennom selve løsningen i stedet for bare å se på løsningen selv.
Vi kommer til å gå over de siste par problemer veldig raskt, 32 og 33.
Bare, igjen, kan slik at online seere se dette.
>> Hvis du slår til problemet ditt 32, som er på side 13,
13 av 16, er problemet 32 ​​om bytteavtaler.
Det var alt om å bytte to heltall.
Det er problemet at vi hadde gått over et par ganger i forelesningen.
Og her, hva vi ber deg om å gjøre en rask minne spor.
Å fylle ut verdiene til variablene som de er på stakken
som koden går gjennom denne swap-funksjon.
Spesielt det vi ser på - jeg kommer til å sette dette iPad ned -
i særdeleshet, hva vi ser på er denne linjen nummerert 6 her.
Og det er nummerert 6 for bare contiguity med forrige problemet.
Hva vi ønsker å gjøre er å vise eller merke staten minne
som det er på den tiden da vi utføre denne linjen nummer 6,
som er effektivt en retur fra vår swap-funksjon her.
Hvis vi bla nedover her, så vi at adressene til alt i minnet ble levert for oss.
Dette er svært viktig, vi vil komme tilbake til det i løpet av et øyeblikk.
Og deretter ned her på bunnen, hadde vi et lite minne diagram som vi kommer til å referere til.
Jeg har faktisk gjort dette ut på min iPad.
Så jeg kommer til å veksle frem og tilbake mellom iPad og denne koden bare for referanse.
>> La oss starte. Først, la oss fokusere på de første par linjer av viktigste akkurat her.
Hvis du vil starte, vi kommer til å starte x til 1 og y 2.
Så vi har to heltall variabler, de begge kommer til å bli plassert på stakken.
Vi kommer til å sette en 1 og en 2 i dem.
Så hvis jeg snur over til min iPad, forhåpentligvis, la oss se -
Apple TV speiling, og der vi går. Okay.
Så hvis jeg snur over til min iPad,
Jeg ønsker å starte x til 1 og y 2.
Vi gjør det ganske enkelt ved å skrive en 1 i boksen merket x
og en 2 i boksen merket y. Ganske enkel.
Så nå la oss gå tilbake til den bærbare datamaskinen, se hva som skjer videre.
Så dette neste linjen er der ting blir vanskelig.
Vi passerer adressen x og adressen y som parametrene a og b til swap-funksjonen.
Adressen x og adressen y er ting som vi ikke kan beregne
uten å referere til disse punktene rett ned her.
Og heldigvis, de to første punktene forteller oss nøyaktig hva svarene er.
Adressen til x minne er 10, og adressen y i minnet er 14.
Så de er verdier som blir vedtatt i som a og b opp toppen i vår swap-funksjon.
Så igjen, bytte tilbake til diagrammet vårt, kan jeg skrive en 10 i en
og en 14 i b.
Nå er dette punktet hvor vi fortsette med swap.
Så blar tilbake til laptop igjen,
Vi ser at måten swap fungerer er jeg først dereferanse A og lagrer resultatet i tmp.
Så dereferanse operatør sier "Hei. Unn innholdet i variabel en som en adresse.
Gå til det du har lagret på denne adressen, og bruke det. "
Hva du legger ut på variabelen skal lagres i vår tmp variabel.
Bla tilbake til iPad.
Hvis vi går for å ta 10, vet vi at adressen 10 er varible x
fordi vi ble fortalt av vår punktet at adressen x minne er 10.
Så vi kan gå dit, få verdien av det, som er 1, som vi ser på iPad vår,
og laste det inn tmp.
Igjen, dette er ikke den endelige innholdet.
Vi kommer til å gå gjennom, og vi vil komme til vårt endelige tilstanden til programmet på slutten.
Men akkurat nå har vi verdien 1 er lagret i tmp.
>> Og det er en rask spørsmål over her.
[Alexander] Er dereferanse operatør - det er bare stjernen rett foran variabel?
>> Ja. Så dereferanse operatør, som vi vende tilbake til vår laptop igjen,
er denne stjernen rett foran.
I den forstand er det - du kontrast det med multiplikasjonsoperatoren
som krever to ting, den dereferanse operatør er en unary operatør.
Bare brukt til en verdi som i motsetning til en binær operator,
hvor du søker på to forskjellige verdier.
Så det er hva som skjer i denne linjen.
Vi lastet verdien 1 og lagret den i vår midlertidige heltallsvariabel.
Neste linje, lagrer vi innholdet i b inn -
eller snarere, lagrer vi innholdet som b peker til på plassen der en peker til.
Hvis vi analyserer dette fra høyre til venstre, skal vi dereferanse b,
vi kommer til å ta 14, skal vi ta tak i heltallet som er der,
og vi kommer til å gå til adressen 10,
og vi kommer til å kaste et resultat av vår dereferanse av b inn i det rommet.
Bla tilbake til vår iPad, hvor vi kan gjøre dette litt mer konkret,
det kan hjelpe hvis jeg skriver tallene på alle adressene her.
Så vi vet at y, er vi på adressen 14, x på adressen 10.
Når vi starter på b, vi dereferanse b, skal vi ta verdien 2.
Vi kommer til å ta denne verdien fordi det er den verdien som bor på adressen 14.
Og vi kommer til å sette det inn i den variabelen som bor på adressen 10,
som er rett der, tilsvarende våre variable x.
Så vi kan gjøre litt for å overskrive her
hvor vi blir kvitt vår 1 og i stedet vi skriver en 2.
Så alt er vel og bra i verden, selv om vi har overskrevet x nå.
Vi har lagret x gamle verdi i vår tmp variabel.
Så vi kan fullføre swap med neste linje.
Bla tilbake til vår laptop.
Nå er alt som gjenstår er å ta innholdet ut av vår midlertidige heltallsvariabel
og lagre dem i den variabelen som bor på den adressen som b holder.
Så vi kommer til å effektivt dereferanse b for å få tilgang til variabelen
som er på den adressen som b holder i det,
og vi kommer til å stappe den verdien som tmp holder i den.
Bla tilbake til iPad gang.
Jeg kan slette denne verdien her, 2,
og i stedet vil vi kopiere en rett inn i den.
Deretter neste linje som utfører, selvfølgelig -
hvis vi vende tilbake til den bærbare - er dette punkt 6,
som er det punktet hvor vi ønsket å ha vår diagram fylt ut.
Så blar tilbake til iPad enda en gang, bare så du kan se det ferdige diagrammet,
du kan se at vi har en 10 i en, en 14 i b, en 1 i tmp, en 2 i x, og en 1 i y.
Er det noen spørsmål om dette?
Betyr dette mer fornuftig, etter å ha vandret gjennom det?
Gjøre mindre fornuftig? Forhåpentligvis ikke. Okay.
>> Pekere er en veldig vanskelig emne.
En av gutta vi jobber med har en svært vanlig ordtak:
"For å forstå pekere, må du først forstå pekere."
Som jeg tror er veldig sant. Det tar en stund å bli vant til det.
Loddtrekning av bilder, er loddtrekning av minne diagrammer som dette svært nyttig,
og når du går gjennom eksempel etter eksempel etter eksempel,
det vil begynne å gjøre litt mer fornuftig og litt mer fornuftig og litt mer fornuftig.
Endelig, en dag, vil du ha det hele helt mestret.
Eventuelle spørsmål før vi går videre til neste problem? OK.
Så vende tilbake til den bærbare datamaskinen.
Det neste problemet vi har er problem nummer 33 på fil I / O.
Zoome inn på dette litt.
Oppgave 33 - Ja?
>> [Daniel] Jeg hadde bare en rask spørsmål. Denne stjernen, eller stjerne,
det heter dereferencing når du bruker en stjerne før.
Hva heter det når du bruker tegnet før?
>> Tegnet er før adressesøk av operatør.
Så la oss bla tilbake.
Oops. Jeg er i zoom-modus så jeg kan egentlig ikke bla.
Hvis vi ser på denne koden veldig raskt akkurat her,
igjen, samme skjer.
Hvis vi ser på denne koden her, på denne linjen hvor vi ringe for å bytte,
tegnet er bare å si "få den adressen variable x liv."
Når kompilatoren kompilerer koden,
det har å faktisk fysisk markere et sted i minnet for alle variabler å leve.
Og så hva kompilatoren kan deretter gjøre når den er utarbeidet alt,
det vet, "Oh, la jeg x på adressen 10. jeg satt y på adressen 14."
Det kan deretter fylle ut disse verdiene for deg.
Så du kan da - det kan da passere dette i og pass & y i tillegg.
Disse gutta få adressen, men de har også, når du passerer dem i swap-funksjonen,
denne type informasjon, dette int * her, forteller kompilatoren,
"Ok, vi kommer til å bli tolke denne adressen som en adresse for en heltallsvariabel."
Som en adresse for en int, som er forskjellig fra adressen av et tegn variabel
fordi en int tar opp, på en 32-bits maskin, tar opp 4 byte av plass,
mens et tegn tar bare opp en byte plass.
Derfor er det viktig å vite også hva er - hva som bor, hva slags verdi
lever på adressen som ble vedtatt i.
Eller adressen som du arbeider med.
På den måten vet du hvor mange byte av informasjon å faktisk laste ut av RAM.
Og så, ja, dette dereferanse operatør, som du spør,
går og tilgang til informasjon på en bestemt adresse.
Så det sier, med dette en variabel her, behandle innholdet i en som en adresse,
gå til denne adressen, og trekk ut, laste inn i prosessoren, last inn i et register
de faktiske verdiene eller innholdet som bor på denne adressen.
Noen flere spørsmål? Dette er gode spørsmål.
Det er mye ny terminologi også.
Det er også slags funky, se & og * på forskjellige steder.
>> OK.
Så tilbake til problemet 33, fil I / O.
Dette var en av de problemene som jeg tror et par ting skjedde.
Ett, er det en ganske ny tråd.
Det ble presentert ganske snart før quizen,
og da tror jeg det var typen som en av de ord problemer i matematikk
der de gir deg mye informasjon, men du faktisk ikke ender opp med å bruke massevis av det.
Den første delen av dette problemet er å beskrive hva en CSV-fil er.
Nå, et CSV-fil, i henhold til beskrivelsen, er en kommadelt fil.
Grunnen til at disse er i det hele tatt interessant, og grunnen til at du bruker dem aldri,
er, fordi, hvor mange av dere noen gang brukte ting som Excel?
Figur fleste av dere har, sannsynligvis, eller vil bruke på et tidspunkt i livet ditt.
Du bruker noe som Excel.
For å få data ut av et Excel-regneark eller gjøre noen form for behandling med det,
Hvis du ønsker å skrive et C-program eller Python program, Java-program,
å håndtere dataene du har lagret der,
en av de vanligste måtene å få det ut er i en CSV-fil.
Og du kan åpne opp Excel og når du går til "Lagre som" dialog,
du kan få ut en faktisk CSV-fil.
>> Nyttig å vite hvordan man skal håndtere disse tingene.
Måten det fungerer på er at det er lik - Jeg mener, det er egentlig etterligne et regneark,
der, som vi ser her, i selve venstre-mest stykke,
Vi har alle de siste navnene.
Så vi har Malan, så Hardison, og deretter Bowden, MacWilliam, og deretter Chan.
Alle de siste navn. Og så komma skiller de siste navnene fra de første navnene.
David, Nate, Rob, Tommy, og Zamyla.
Jeg har alltid blande Robby og Tom.
Og så, til slutt, er den tredje kolonnen e-postadressene.
Når du forstår det, er resten av programmet ganske grei å gjennomføre.
Hva vi har gjort for å etterligne den samme strukturen i vår C program
er vi har brukt en struktur.
Vi vil begynne å spille med disse litt mer også.
Vi så dem for første litt i oppgavesettet 3, da vi arbeider med ordbøker.
Men denne ansatte struct lagrer et etternavn, fornavn, og en e-post.
Akkurat som vår CSV-filen ble lagring.
Så dette er bare å konvertere fra ett format til et annet.
Vi har til å konvertere, i dette tilfellet, en stab struct inn en linje,
en kommaseparert linje, akkurat sånn.
Gjør det fornuftig? Dere har alle tatt quizen,
så jeg tenke at du har minst hadde litt tid til å tenke på dette.
>> I leie-funksjonen, spør problemet oss å ta i - vi vil zoome inn på dette litt -
ta i en stab struktur, en stab struct, med navn s,
og legge innholdet til vår staff.csv fil.
Det viser seg at dette er ganske grei å bruke.
Vi vil slags leke seg med disse funksjonene litt mer i dag.
Men i dette tilfellet er fprintf funksjonen virkelig nøkkelen.
Så med fprintf, kan vi skrive ut, akkurat som dere har brukt printf hele denne sikt.
Du kan printf en linje til en fil.
Så i stedet for bare å gjøre den vanlige printf samtale der du gi den formatstrengen
og deretter erstatte alle variablene med følgende argumenter,
med fprintf, er din aller første argumentet i stedet filen du ønsker å skrive til.
Hvis vi skulle se på dette i apparatet, for eksempel, mann fprintf,
Vi kan se forskjellen mellom printf og fprintf.
Jeg skal zoome inn her litt.
Så med printf, gir vi det et format streng, og deretter påfølgende argumenter
er alle variablene for erstatning eller erstatning i vår formatstrengen.
Mens med fprintf, er det første argumentet faktisk dette fil * kalles en bekk.
>> Flytte tilbake hit til leie vår,
Vi har allerede fått vår fil * stream åpnet for oss.
Det er hva denne første linjen gjør den åpner staff.csv fil,
det åpner det i append modus, og alt som er igjen for oss å gjøre, er
skrive bemanningsstrukturen til filen.
Og, la oss se, jeg ønsker å bruke iPad?
Jeg vil bruke iPad. Vi har annullert - la oss sette dette på bordet slik at jeg kan skrive litt bedre -
ugyldiggjøre leie og det tar i ett argument, en stab struktur kalt s.
Fikk våre bukseseler, har vi vår fil * heter filen,
Vi har vår fopen linjen gitt til oss,
og jeg vil bare skrive det som prikker siden det er allerede i pedia.
Og deretter på vår neste linje, vi kommer til å ringe til fprintf
og vi kommer til å passere i filen som vi ønsker å skrive til,
og deretter våre formatstrengen, som -
Jeg skal la dere fortelle meg hva det ser ut som.
Hva med deg, Stella? Vet du hva den første delen av formatstrengen ser ut?
[Stella] Jeg er ikke sikker. >> Gjerne spørre Jimmy.
Vet du, Jimmy?
[Jimmy] Vil det bare være sist? Jeg vet ikke. Jeg er ikke helt sikker.
>> Ok. Hva med, gjorde noen få dette riktig på eksamen?
Nei vel.
Det viser seg at her alt vi trenger å gjøre er vi ønsker hver del av våre ansatte struktur
som skal skrives ut som en streng i fil vår.
Vi bare bruke strengen substitusjon tegnet tre forskjellige tider fordi vi har et etternavn
etterfulgt av komma, deretter en fornavn etterfulgt av et komma,
og så til slutt e-postadressen som er fulgt - som ikke
montering på skjermen min - men det er etterfulgt av en ny linje karakter.
Så jeg kommer til å skrive det bare der nede.
Og deretter følge vår formatstrengen,
vi bare har erstatninger, som vi har tilgang til via dot notasjon
som vi så i oppgavesettet 3.
Vi kan bruke s.last, s.first, og s.email
å erstatte i de tre verdiene i vår formatstrengen.
Så hvordan gikk det gå? Fornuftig?
Ja? Nei? Muligens? Okay.
>> Den siste tingen som vi gjør etter at vi har skrevet ut og etter at vi har åpnet våre filen:
når vi har åpnet en fil, har vi alltid huske å lukke den.
Fordi ellers vil vi ende opp lekker minnet,
bruker opp fildeskriptorer.
Så for å lukke det, hvilken funksjon bruker vi? Daniel?
[Daniel] fclose? >> Fclose, akkurat.
Så den siste delen av dette problemet var å skikkelig lukke filen, ved hjelp av fclose funksjon,
som ser akkurat sånn.
Ikke altfor gal.
Cool.
Så det er problem 33 på quiz.
Vi vil ha definitivt mer fil I / O kommer opp.
Vi vil gjøre litt mer i foredraget i dag, eller i § dag,
fordi det er det som kommer til å danne hoveddelen av denne kommende pset.
La oss gå videre fra quizen på dette punktet. Ja?
>> [Charlotte]] Hvorfor fclose (fil) i stedet for fclose (staff.csv)?
>> Ah. Fordi det viser seg at - så spørsmålet, som er en stor en,
er hvorfor, når vi skriver fclose, skriver vi fclose (fil) star variabel
i motsetning til filnavnet, staff.csv? Er det riktig? Ja.
Så la oss ta en titt. Hvis jeg bytter tilbake til min laptop,
og la oss se på fclose funksjonen.
Så fclose funksjonen stenger en bekk og det tar i pekeren til bekken som vi ønsker å lukke,
i motsetning til den faktiske filnavnet som vi ønsker å lukke.
Og dette er fordi bak kulissene, når du ringer til fopen,
når du åpner opp en fil, kan du faktisk tildele minne til å lagre informasjon om filen.
Så du har filpekeren som har informasjon om filen,
slik som det er åpent, størrelse, hvor du befinner deg i filen,
slik at du kan gjøre lesing og skriving samtaler til dette bestemte stedet i filen.
Du ender opp med å stenge pekeren stedet for å lukke filnavnet.
>> Ja? [Daniel] Så for å bruke leie, vil du si - hvordan få det brukeren innspill?
Ikke handler fprintf som GetString i den forstand at det vil bare vente på brukerens input
og ber deg om å skrive dette - eller vente for deg å skrive disse tre tingene i?
Eller trenger du å bruke noe til å gjennomføre leie?
>> Ja. Så vi er ikke - spørsmålet var, hvordan vi får brukerundersøkelser
for å gjennomføre leie? Og det vi har her er den som ringer for hire,
vedtatt i denne ansatte struct med alle data som er lagret i struct allerede.
Så er fprintf stand til å bare skrive at data direkte til filen.
Det er ingen ventetid for brukerens input.
Brukeren er allerede gitt innspill ved riktig å sette den i denne ansatte struct.
Og ting, selvfølgelig, ville brekke hvis noen av disse pekere var null,
så vi rulle opp her og ser vi på struct vår.
Vi har streng sist, string først, streng e-post.
Vi vet nå at alle de virkelig, under panseret, er char * variabler.
Som kan eller ikke kan peke mot null.
De kan peke mot minnet på haugen,
kanskje minne på stakken.
Vi vet ikke, men hvis noen av disse pekere er null eller ugyldig,
at det vil definitivt krasje vår utleie funksjon.
Det var noe som var litt utenfor rammen av eksamen.
Vi er ikke bekymre det.
Flott. Okay. Så går videre fra quiz.
>> La oss lukke denne fyren, og vi kommer til å se på pset 4.
Så hvis dere ser på pset spec, når du kan få tilgang til den, cs50.net/quizzes,
Vi kommer til å gå gjennom noen av avsnittet problemer i dag.
Jeg rulle ned - del spørsmål begynner på den tredje siden av pset spec.
Og første del ber deg om å gå og se kort på omdirigere og rør.
Som var slags en kul kort, viser deg noen nye, kule kommandolinje triks som du kan bruke.
Og så har vi et par spørsmål til deg også.
Det første spørsmålet om bekker, som printf skriver som standard,
Vi slags berørt bare litt et øyeblikk siden.
Dette fprintf at vi var bare diskutere tar i en fil * strøm som argument sin.
fclose tar i en fil * strøm også,
og returverdien av fopen gir deg en fil * strøm også.
Grunnen til at vi ikke har sett dem før når vi har jobbet med printf
er fordi printf har en standard strøm.
Og standard stream som den skriver
du vil finne ut om på kort.
Så definitivt ta en titt på den.
>> I dagens avsnitt, skal vi snakke litt om GDB,
siden mer kjent du er med det, jo mer praksis du får med det,
bedre i stand vil være å faktisk jakte ned feil i din egen kode.
Dette gjør prosessen med feilsøking opp enormt.
Så ved å bruke printf, hver gang du gjør det du må rekompilere koden,
må du kjøre den på nytt, noen ganger må du flytte printf samtale rundt,
kommentere ut kode, tar det bare en stund.
Vårt mål er å prøve og overbevise deg om at med GDB, kan du i hovedsak
printf noe som helst i koden din, og du trenger aldri å rekompilere det.
Du trenger aldri å starte og fortsette å gjette hvor du printf neste.
Det første du må gjøre er å kopiere denne linjen og få delkoden ut av nettet.
Jeg kopiering denne linjen med kode som sier, "wget ​​http://cdn.cs50.net".
Jeg kommer til å kopiere den.
Jeg kommer til å gå over til apparatet mitt, zoome ut slik at du kan se hva jeg gjør,
lime den inn der, og når jeg trykker på Enter, dette wget kommando bokstavelig er en web får.
Det kommer til å trekke ned denne filen ut av Internett,
og det kommer til å spare det til gjeldende katalog.
Nå hvis jeg listen min nåværende katalog du kan se at jeg har fått denne section5.zip fil rett der.
Den måten å forholde seg til at fyren er å pakke den,
som du kan gjøre i kommandolinjen, akkurat som dette.
Section5.zip.
Det vil pakke den, opprette mappen for meg,
blåse hele innholdet, legg dem i det.
Så nå kan jeg gå inn i min seksjon 5 katalogen ved hjelp av cd-kommandoen.
Tømme skjermen ved hjelp av klare. Så tømme skjermen.
Nå har jeg fått en fin ren terminal å forholde seg til.
>> Nå hvis jeg føre opp alle filene som jeg ser i denne katalogen,
du ser at jeg har fire filer: buggy1, buggy2, buggy3 og buggy4.
Jeg har også fått sine tilsvarende. C-filer.
Vi kommer ikke til å se på. C-filene for nå.
I stedet, vi kommer til å bruke dem når vi åpner opp GDB.
Vi har holdt dem rundt slik at vi har tilgang til selve kildekoden når vi bruker GDB,
men målet for denne delen av seksjonen er å tinker rundt med GDB
og se hvordan vi kan bruke det til å finne ut hva som går galt med hver av disse fire buggy programmer.
Så vi skal bare rundt i rommet veldig raskt,
og jeg kommer til å be noen om å kjøre en av de buggy programmer,
og så får vi gå som en gruppe gjennom GDB, og vi får se hva vi kan gjøre for å fikse disse programmene,
eller minst identifisere hva som går galt i hver av dem.
La oss starte på her med Daniel. Vil du kjøre buggy1? La oss se hva som skjer.
[Daniel] Det står at det er et program feil. >> Ja. Akkurat.
Så hvis jeg kjører buggy1, får jeg en SEG feil.
På dette punktet, jeg kunne gå og åpne opp buggy1.c,
prøve og finne ut hva som går galt,
men en av de mest motbydelige ting om dette segmentet feil feil
er at det ikke forteller deg om hvilken linje av programmet tingene faktisk gikk galt og blakk.
Du slags nødt til å se på koden
og finne ut ved hjelp gjetning og sjekk eller printf for å se hva som går galt.
En av de kuleste tingene om GDB er at det er veldig, veldig lett
å finne ut linjen der du programmet krasjer.
Det er helt verdt det å bruke den, selv om bare for det.
Så for å starte opp GDB, skriver jeg GDB, og så gir jeg den banen til den kjørbare som jeg ønsker å kjøre.
Her jeg skriver GDB ./buggy1.
Trykk Enter. Gir meg alt dette informasjon om opphavsrett,
og ned her vil du se denne linjen som sier "Reading symboler fra / home /
jharvard/section5/buggy1. "
Og hvis alt går bra, vil du se det skrive ut en melding som ser slik ut.
Det skal lese symboler, vil det si "Jeg leser symboler fra kjørbar fil,"
og da vil det ha denne "ferdig"-melding over her.
Hvis du ser noen annen variant av dette, eller ser du det ikke kunne finne symbolene
eller noe sånt, hva det betyr er at du bare ikke har kompilert din kjørbar riktig.
Når vi kompilere programmer for bruk med GDB, må vi bruke den spesielle-g flagget,
og det er gjort som standard hvis du kompilere programmer, bare ved å skrive gjøre
eller gjøre buggy eller gjøre gjenopprette, noen av de.
Men hvis du kompilere manuelt med Clang, så du må gå inn og ta det-g flagget.
>> På dette punktet, nå som vi har våre GDB prompt,
det er ganske enkelt å kjøre programmet.
Vi kan enten skrive løp, eller vi kan bare skrive r.
De fleste GDB kommandoer kan bli forkortet.
Vanligvis til bare én eller et par bokstaver, som er ganske fin.
Så Saad, hvis du skriver r og trykk Enter, hva skjer?
[Saad] Jeg fikk SIGSEGV, segmentering feil, og deretter alt dette gobbledygook.
>> Ja.
Som vi ser på skjermen akkurat nå, og som Saad sa,
når vi skriver kjøre eller r og trykk Enter, vi fortsatt får den samme segmentet feil.
Så bruker GDB løser ikke vårt problem.
Men det gir oss noen gobbledygook, og det viser seg at dette gobbledygook
faktisk forteller oss hvor det skjer.
Å analysere denne litt, er dette første bit funksjonen der alt som går galt.
Det er denne __ strcmp_sse4_2, og det forteller oss at det skjer i denne filen
kalt sysdeps/i386, alt dette, igjen, en slags rot - men linjen 254.
Det er litt vanskelig å analysere. Vanligvis når du ser ting som dette,
det betyr at det er SEG forkastninger i en av system-biblioteker.
Så noe å gjøre med strcmp. Dere har sett strcmp før.
Ikke altfor gal, men betyr dette at strcmp er ødelagt eller at det er et problem med strcmp?
Hva tror du, Alexander?
[Alexander] Er det - er 254 linjen? Og - ikke den binære, men det er ikke deres tak,
og så er det et annet språk for hver funksjon. Er at 254 i denne funksjonen, eller -?
>> Det er linje 254. Det ser ut som i denne. S fil, så det er assemblykode sannsynligvis.
>> Men jeg antar det mer presserende ting er, fordi vi har fått en SEG feil,
og det ser ut som det kommer fra strcmp funksjon,
betyr dette, da, er at strcmp brutt?
Det burde ikke, forhåpentligvis. Så bare fordi du har en segmentering feil
i en av systemet fungerer, betyr vanligvis at du bare ikke ha kalt det riktig.
Den raskeste tingen å gjøre for å finne ut hva som faktisk skjer
når du ser noe sprøtt som dette, når du ser en SEG feil,
spesielt hvis du har et program som er å bruke mer enn bare main,
er å bruke en tilbakesporing.
Jeg forkort tilbakesporing ved å skrive bt, i motsetning til den fullstendige tilbakesporing ordet.
Men Charlotte, hva skjer når du skriver bt og trykk Enter?
[Charlotte] Det viser meg to linjer, linje 0 og 1 linje.
>> Ja. Så linje 0 og linje 1.
Dette er de faktiske stack rammer som var tiden i spill når programmet krasjet.
Starter fra øverste ramme, 0 ramme, og gå til nederste, som er rammen en.
Vår øverste rammen er strcmp ramme.
Du kan tenke på dette som ligner på det problemet vi var bare å gjøre på quiz med pekere,
der vi hadde bytte stabelen rammen på toppen av hoved stabelen ramme,
og vi hadde de variablene som swap var bruker på toppen av de variablene som viktigste var med.
Her er vår krasj skjedde i vår strcmp funksjon, som ble kalt av våre viktigste funksjon,
og backtrace gir oss ikke bare funksjonene som ting mislyktes,
men det er også å fortelle oss hvor alt ble kalt fra.
Så hvis jeg ruller over en litt mer til høyre,
Vi kan se at ja, vi var på linje 254 av denne strcmp-sse4.s fil.
Men samtalen ble gjort på buggy1.c, 6 linje.
Så det betyr at vi kan gjøre - er at vi kan bare gå sjekke ut og se hva som skjer
på buggy1.c, 6 linje.
Igjen, det er et par måter å gjøre dette på. Det ene er å gå ut av GDB
eller har koden åpnes i et annet vindu og kryssreferanse.
Det, i seg selv, er ganske praktisk fordi nå hvis du er på kontortid
og du har en SEG feil og TF har lurer på hvor alt var å bryte,
du kan bare si: "Å, linje 6. jeg vet ikke hva som skjer,
men noe om linje 6 forårsaker mitt program for å bryte. "
Den andre måten å gjøre det er at du kan bruke denne kommandoen kalles liste i GDB.
Du kan også forkorte det med l..
Så hvis vi treffer l, hva vi får her?
Vi får en hel haug med rare ting.
Dette er selve monteringen koden
som er i strcmp_sse4_2.
Dette ser slags funky,
og grunnen til at vi får dette er fordi akkurat nå,
GDB har oss i ramme 0.
>> Så hver gang vi ser på variabler, helst vi ser på kildekoden,
vi ser på kildekoden som gjelder stabelen rammen vi er nå i.
Så for å få noe meningsfylt, må vi
flytte til en stabel ramme som gjør mer fornuftig.
I dette tilfellet, vil den viktigste stabelen rammen gjør litt mer fornuftig,
fordi det var faktisk koden som vi skrev.
Ikke strcmp koden.
Måten du kan flytte mellom rammer, i dette tilfellet, fordi vi har to,
vi har 0 og 1,
du gjøre det med opp og ned kommandoer.
Hvis jeg flytter opp ett bilde,
nå er jeg i hovedsak stabelen rammen.
Jeg kan flytte ned for å gå tilbake til der jeg var,
gå opp igjen, gå ned igjen, og gå opp igjen.
Hvis du noen gang gjøre programmet i GDB, du får en krasj, får du tilbakesporing,
og du ser at det er i noen fil som du ikke vet hva som skjer.
Du prøver listen, betyr ikke koden ser kjent ut for deg,
ta en titt på dine rammer og finne ut hvor du er.
Du er sannsynligvis i feil bunke rammen.
Eller i det minste du er i en stabel ramme som ikke er en som du virkelig kan feilsøke.
Nå som vi er i riktig stabelen rammen, vi er i hovedsak
nå kan vi bruke list for å finne ut hva linjen var.
Og du kan se det, det skrives det for oss her.
Men vi kan treffe liste alle de samme, og listen gir oss denne fine utskriften
av selve kildekoden som skjer her.
>> Spesielt kan vi se på linje 6..
Vi kan se hva som skjer her.
Og det ser ut som vi gjør en streng sammenligning
mellom streng "CS50 rocks" og argv [1].
Noe om dette ble krasj.
Så Missy, har du noen tanker om hva som kan skjer her?
[Missy] Jeg vet ikke hvorfor det er krasj. >> Du vet ikke hvorfor det er krasj?
Jimmy, noen tanker?
[Jimmy] Jeg er ikke helt sikker, men siste gang vi brukte streng sammenligne,
eller strcmp, hadde vi som tre forskjellige saker etter det.
Vi har ikke en ==, tror jeg ikke, midt i den første linjen.
I stedet ble det delt inn i tre, og en var == 0,
var <0, tror jeg, og en var> 0.
Så kanskje noe sånt? >> Ja. Så det er dette problemet
av gjør vi sammenligningen riktig?
Stella? Noen tanker?
[Stella] Jeg er ikke sikker. >> Ikke sikker. Daniel? Tanker? Okay.
Det viser seg hva som skjer akkurat her er når vi kjørte programmet
og vi fikk SEG feil, da du kjørte programmet for første gang, Daniel,
gjorde du gi det noen kommandolinjeargumentene?
[Daniel] Nei >> Nei I så tilfelle, hva er verdien av argv [1]?
>> Det er ingen verdi. >> Høyre.
Vel er det ingen passende strengverdi.
Men det er noen verdi. Hva er verdien som blir lagret der inne?
>> En søppel verdi? >> Det er enten en søppel verdi eller, i dette tilfellet,
enden av argv matrisen avsluttes alltid med null.
Så hva fikk faktisk lagret i det null.
Den andre måten å løse dette, snarere enn å tenke det gjennom,
er å prøve å skrive den ut.
Det er der jeg sa at å bruke GDB er stor,
fordi du kan skrive ut alle variabler, alle verdiene som du vil
bruker denne handy-dandy p kommandoen.
Så hvis jeg skriver p og da jeg skriver verdien av en variabel eller navnet på en variabel,
sier argc, ser jeg at argc er en.
Hvis jeg ønsker å skrive ut argv [0], kan jeg gjøre det akkurat sånn.
Og som vi så, argv [0] er alltid navnet på programmet,
alltid navnet på den kjørbare.
Her ser du det har det fullstendige navnet.
Jeg kan også skrive ut argv [1] og se hva som skjer.
>> Her fikk vi denne typen mystiske verdi.
Vi fikk denne 0x0.
Husk på begynnelsen av begrepet når vi snakket om heksadesimale tall?
Eller at lite spørsmål på slutten av pset 0 om hvordan å representere 50 i hex?
Måten vi skriver hex tall i CS, bare ikke å forvirre oss
med desimaltall, er vi alltid prefiks dem med 0x.
Så dette 0x prefikset alltid betyr bare tolke følgende nummer som et heksadesimalt tall,
ikke som en streng, ikke som et desimaltall, ikke som et binært tall.
Siden antallet 5-0 er et gyldig tall i heksadesimal.
Og det er et tall i desimal, 50.
Så dette er bare hvordan vi disambiguate.
Så 0x0 betyr heksadesimal 0, som også er desimal 0, binære 0.
Det er bare verdien 0.
Det viser seg at dette er hva null er, faktisk, i minnet.
Null er bare 0.
Her elementet lagret på argv [1] er null.
Så vi prøver å sammenligne vår "CS50 rocks" strengen til en null-streng.
Så dereferencing null, prøver å få tilgang ting på null,
de er vanligvis kommer til å forårsake noen form for segmentering feil eller andre dårlige ting til å skje.
Og det viser seg at strcmp ikke kontrollere
om du har gått i en verdi som er null.
Snarere, det bare går fremover, prøver å gjøre sine ting,
og hvis det SEG feil, SEG det feil, og det er problemet. Du må gå fikse det.
Veldig raskt, kan hvordan vi kan løse dette problemet? Charlotte?
[Charlotte] Du kan sjekke med hvis.
Så hvis argv [1] er null, == 0, og deretter gå tilbake 1, eller noe [uforståelig].
>> Ja. Så det er en fin måte å gjøre det, som vi kan sjekke for å se,
verdien vi er i ferd med å passere inn strcmp, argv [1], er null det?
Hvis det er null, så kan vi si greit, abort.
>> En mer vanlig måte å gjøre dette på er å bruke argc verdi.
Du kan se her i begynnelsen av viktigste,
vi utelatt det første test som vi vanligvis gjør når vi bruker kommandolinjeargumenter,
som er å teste hvorvidt våre argc verdi er hva vi forventer.
I dette tilfellet, vi ventet minst to argumenter,
navnet på program pluss en annen.
Fordi vi er i ferd med å bruke det andre argumentet her.
Så å ha en slags test på forhånd, før vår strcmp samtale
at tester hvorvidt argv er minst 2, vil også gjøre det samme slags ting.
Vi kan se om det fungerer ved å kjøre programmet på nytt.
Du kan alltid starte program innen GDB, som er virkelig fint.
Du kan kjøre, og når du passerer i argumentene til programmet,
du passerer dem i når du kaller kjøre, ikke når du starter opp GDB.
På den måten kan du holde påkalle programmet med forskjellige argumenter hver gang.
Så kjøre, eller igjen, kan jeg skrive r, og la oss se hva som skjer hvis vi skriver "Hei".
Det vil alltid spørre deg om du ønsker å starte det fra begynnelsen igjen.
Vanligvis vil du starte det fra begynnelsen igjen.
Og på dette punktet, det starter den igjen, skrives det ut
programmet som vi kjører, buggy1, med argumentet hallo,
og det skrives denne standarden ut, det sier "Du får et D," trist ansikt.
Men vi gjorde ikke SEG feil. Det sies at prosessen gått som normalt.
Så det ser ganske bra.
Ingen flere SEG feil, gjorde vi det siste,
så det ser ut som det var faktisk SEG feil bug som vi får.
Dessverre, forteller det oss at vi får en D.
>> Vi kan gå tilbake og se på koden og se hva som skjer der
å finne ut hva som var - hvorfor det var å fortelle oss at vi fikk en D.
La oss se, her var dette printf si at du fikk en D.
Hvis vi skriver liste, som du fortsette å skrive liste, holder det gjentar seg gjennom programmet,
så det vil vise deg de første linjene av programmet.
Så det vil vise deg de neste linjene, og neste blings og neste del.
Og det vil fortsette å prøve å gå ned.
Og nå skal vi få til "linje nummer 16 er ute av rekkevidde."
Fordi den har bare 15 linjer.
Hvis du kommer til dette punktet, og du lurer på, "Hva gjør jeg?" kan du bruke kommandoen help.
Bruk hjelp og deretter gi det navnet på en kommando.
Og du ser GDB gir oss alle denne typen ting.
Står det: "Uten argument, viser ti linjer etter eller rundt forrige notering.
List - viser de ti linjer før - "
Så la oss prøve å bruke liste minus.
Og som viser de 10 linjene forrige, du kan spille rundt med liste litt.
Du kan gjøre listen, listen -, kan du selv gi listen en rekke, som liste 8,
og det vil liste de 10 linjene rundt linje 8.
Og du kan se hva som skjer her er at du har en enkel if else.
Hvis du skriver inn CS50 steiner, skrives det ut "Du får en A."
Ellers er det skrives ut "Du får en D."
Bummer byen. OK. Ja?
>> [Daniel] Så når jeg prøvde å gjøre CS50 bergarter uten anførselstegn,
det står "Du får en D."
Jeg trengte anførselstegn for å få det til å fungere, hvorfor er det?
>> Ja. Det viser seg at når - dette er en annen morsom liten godbit -
når du kjører programmet, hvis vi kjører den og vi skriver i CS50 bergarter,
akkurat som Daniel sa han gjorde, og du trykker på Enter,
det står fortsatt vi får en D.
Og spørsmålet er, hvorfor er dette?
Og det viser seg at både vår terminal og GDB analysere disse som to separate argumenter.
Fordi når det er en plass, som er underforstått som
det første argumentet endte, den neste argumentet er i ferd med å begynne.
Den måten å kombinere dem i to, eller sorry, i ett argument,
er å bruke anførselstegn.
Så nå, hvis vi setter det i anførselstegn og kjøre den på nytt, får vi en A.
Så bare for å oppsummere, er ingen sitater, CS50 og steiner analyseres som to separate argumenter.
Med sitater, er det tolket som et argument helt.
>> Vi kan se dette med et stoppunkt.
Så langt har vi kjørt programmet vårt, og det er kjørt
inntil enten det SEG feil eller treff en feil
eller til den har gått ut og alle har vært helt fint.
Dette er ikke nødvendigvis den mest nyttige ting, fordi noen ganger
du har en feil i programmet, men det er ikke forårsaker en segmentering feil.
Det er ikke forårsaker programmet til å stoppe eller noe sånt.
Måten å få GDB til pause programmet på et bestemt punkt
er å sette et stoppunkt.
Du kan enten gjøre dette ved å sette et stoppunkt på en funksjon navn
eller du kan sette et stoppunkt på en bestemt linje med kode.
Jeg liker å sette stoppunkter på funksjon navn, fordi - lett å huske,
og hvis du faktisk gå inn og endre kildekoden opp litt,
deretter din stoppunkt vil faktisk bo på samme sted i koden.
Mens hvis du bruker linje tall, og linjenummer endre
fordi du legger til eller slette noen kode, deretter din brytningspunkt er alle helt ødelagt.
En av de vanligste tingene jeg gjør er å angi et stoppunkt på den viktigste funksjonen.
Ofte jeg starter opp GDB, jeg skriver b viktigste, trykk på Enter, og som vil sette et stoppunkt
på den viktigste funksjonen som bare sier, "Pause programmet så snart du begynner å kjøre,"
og på den måten, når jeg kjører mitt program med, sier CS50 bergarter som to argumenter
og trykk Enter, blir det til den viktigste funksjonen og den stopper rett ved den aller første linje,
rett før den vurderer strcmp funksjonen.
>> Siden jeg er satt på pause, nå kan jeg begynne å rote rundt og se hva som skjer
med alle de forskjellige variabler som er gått inn i programmet mitt.
Her kan jeg skrive ut argc og se hva som skjer.
Se at argc er 3, fordi det er fikk 3 forskjellige verdier i den.
Det fikk navnet på programmet, det har det første argumentet og det andre argumentet.
Vi kan skrive dem ut ved å se på argv [0], argv [1], og argv [2].
Så nå kan du også se hvorfor dette strcmp samtalen kommer til å mislykkes,
fordi du ser at det gjorde dele opp CS50 og bergarter i to separate argumenter.
På dette punktet, når du har truffet et stoppunkt, kan du fortsette å gå gjennom programmet
linje for linje, i motsetning til å starte programmet på nytt.
Så hvis du ikke ønsker å starte programmet på nytt og bare fortsette herfra,
kan du bruke continue kommandoen og fortsetter vil kjøre programmet til slutt.
Akkurat som det gjorde her.
Men hvis jeg starter programmet, CS50 steiner, treffer det min stoppunkt igjen,
og denne gangen, hvis jeg ikke ønsker å bare gå hele veien gjennom resten av programmet,
Jeg kan bruke den neste kommandoen, som jeg også forkorte med n.
Og dette vil gå gjennom programmet linje for linje.
Så du kan se på som ting utføre, som variabler endring, som ting blir oppdatert.
Som er ganske fin.
Den andre kule ting er heller enn å gjenta den samme kommandoen over og over og over igjen,
hvis du bare trykke Enter - så her ser du jeg har ikke skrevet i noe -
hvis jeg bare trykke Enter, vil det gjenta forrige kommando,
eller forrige GDB kommandoen at jeg bare satt i.
Jeg kan fortsette å trekke inn og det vil holde stepping gjennom min kode linje for linje.
Jeg vil oppfordre dere til å gå sjekke ut de andre buggy programmer også.
Vi har ikke tid til å komme gjennom alle av dem i dag i snitt.
Kildekoden er der, så du kan slags se hva som skjer
bak kulissene hvis du blir virkelig stakk,
men i det minste, bare øve starter opp GDB,
kjører programmet før det bryter på deg,
få backtrace, finne ut hvilken funksjon ulykken var i,
hvilken linje det var på, skrive ut noen variable verdier,
bare så du får en følelse for det, fordi det vil virkelig hjelpe deg fremover.
På dette punktet, vi kommer til å slutte ut av GDB, som du gjør med slutte eller bare q.
Hvis programmet er i midten av å kjøre fortsatt, og det har ikke gått ut,
det vil alltid spørre deg: «Er du sikker på at du virkelig ønsker å slutte?"
Du kan bare trykke ja.
>> Nå skal vi se på neste problemet vi har, som er katten programmet.
Hvis du ser på kort på omdirigere og rør, vil du se at Tommy bruker dette programmet
som skriver utgangspunktet alle resultatet av en fil på skjermen.
Så hvis jeg kjører cat, dette er faktisk en innebygd program til apparatet,
og hvis du har Mac kan du gjøre dette på din Mac også, hvis du åpner opp terminalen.
Og vi - katt, la oss si, cp.c, og trykk på Enter.
Hva dette gjorde, hvis vi blar opp litt og se hvor vi kjørte linjen,
eller hvor vi kjørte katten kommandoen, det bokstavelig talt bare skrives ut innholdet i cp.c til skjermen vår.
Vi kan kjøre den på nytt, og du kan sette i flere filer sammen.
Så du kan gjøre katten cp.c, og da kan vi også sette sammen den kategori C-filen,
som er et program vi er i ferd med å skrive,
og det vil skrive ut begge filene tilbake til tilbake til skjermen vår.
Så hvis vi blar opp litt, ser vi at når vi kjørte denne katten cp.c, kategori C,
først det skrives ut cp filen, og deretter under den, skrives det ut, kategori C filen rett ned her.
Vi kommer til å bruke dette til å bare få våre føtter våt.
Lek litt med enkel utskrift til terminalen, se hvordan det fungerer.
Hvis dere åpne opp med gedit kategori C, trykk Enter,
kan du se programmet som vi er i ferd med å skrive.
Vi har tatt dette fint kjele plate, så vi trenger ikke å bruke tid på å skrive alt ut.
Vi også sjekke antall argumenter gikk i.
Vi skriver ut en fin bruk melding.
>> Dette er den slags ting som, igjen, som vi har vært snakket om,
det er nesten som muskel minne.
Bare husk å holde gjør det samme slags ting
og alltid skrive ut noen form for nyttig melding
slik at folk vet hvordan de skal kjøre programmet.
Med katten, er det ganske enkelt, vi bare kommer til å gå gjennom alle de forskjellige argumentene
som ble sendt til vårt program, og vi kommer til å skrive ut
innholdet ut til skjermen en om gangen.
For å skrive ut filer ut til skjermen, vi kommer til å gjøre noe lignende
til hva vi gjorde på slutten av quizen.
På slutten av quizen, som leier program, måtte vi åpne opp en fil,
og da måtte vi ut på den.
I dette tilfellet, vi kommer til å åpne opp en fil, og vi kommer til å lese fra det stedet.
Så vi kommer til å skrive ut, i stedet for til en fil, kommer vi til å skrive ut på skjermen.
Så skriver til skjermen du har alle gjort før med printf.
Så det er ikke så gal.
Men å lese en fil er slags merkelig.
Vi vil gå gjennom det en liten bit av gangen.
Hvis dere går tilbake til det siste problemet på quiz, problemet 33,
den første linjen som vi kommer til å gjøre her, åpne filen, er svært likt det vi gjorde der.
Så Stella, hva betyr denne linjen ser ut, når vi åpner en fil?
[Stella] Capital FIL *, fil - >> Ok. >> - Er lik fopen. >> Yup.
Som i dette tilfellet er? Det er i kommentaren.
>> Det er i kommentaren? argv [i] og r?
>> Nettopp. Rett på. Så Stella er helt rett.
Dette er hva linjen ser ut.
Vi kommer til å få en filstrøm variabel, lagre den i en fil *, så alle caps,
FIL, *, og navnet på denne variabelen vil være fil.
Vi kan kalle det hva vi vil. Vi kan kalle det first_file, eller file_i, hva vi ønsker.
Og så navnet på filen ble vedtatt i på kommandolinjen til dette programmet.
Så det er lagret i argv [i,] og vi kommer til å åpne denne filen i lesemodus.
Nå som vi har åpnet filen, er det ting som vi alltid må huske å gjøre
når vi har åpnet en fil? Lukke den.
Så Missy, hvordan vi lukke en fil?
[Missy] fclose (fil) >> fclose (fil). Akkurat.
Flott. Okay. Hvis vi ser på dette å gjøre kommentaren her,
står det: "Åpen argv [i] og skrive ut innholdet til stdout."
>> Standard ut er et merkelig navn. Stdout er bare vår måte å si
vi ønsker å skrive det til terminalen, ønsker vi å skrive det til standard ut-strømmen.
Vi kan faktisk bli kvitt denne kommentaren her.
Jeg kommer til å kopiere den og lime den siden det er hva vi gjorde.
På dette punktet, nå må vi lese filen bit for bit.
Vi har diskutert et par måter å lese filer.
Hvilke er dine favoritter så langt?
Hvilke måter har du sett eller husker du, for å lese filer?
[Daniel] fread? >> Fread? Så fread er én. Jimmy, vet du noen andre?
[Jimmy] Nei >> Ok. Nope. Charlotte? Alexander? Noen andre? Okay.
Så de andre som er fgetc, er en som vi vil bruke mye.
Det er også fscanf, dere ser et mønster her?
De alle begynner med f. Noe å gjøre med en fil.
Det er fread, fgetc, fscanf. Disse er alle av lesningen funksjoner.
For å skrive har vi fwrite, har vi fputc stedet for fgetc.
Vi har også fprintf liker vi så på quiz.
Siden dette er et problem som innebærer å lese fra en fil,
vi kommer til å bruke en av disse tre funksjonene.
Vi kommer ikke til å bruke disse funksjonene her nede.
Disse funksjonene er alle funnet i standard I / O biblioteket.
Så hvis du ser på toppen av dette programmet,
du kan se at vi allerede har tatt topptekstfilen for standard I / O-bibliotek.
Hvis vi ønsker å finne ut hvilken som vi ønsker å bruke,
Vi kan alltid åpne opp mannen sidene.
Så vi kan skrive mann stdio
og lese alt om stdio input og output funksjoner i C.
Og vi kan allerede se oh, se. Det er nevne fgetc, det å nevne fputc.
Så du kan bore ned litt og se på, sier fgetc
og se på sin mann siden.
Du kan se at det går sammen med en hel haug med andre funksjoner:
fgetc, fgets, getc, getchar, blir, ungetc, og input av tegn og strenger.
Så dette er hvordan vi leser i tegn og strenger fra filer fra standard inngang,
som er hovedsakelig fra brukeren.
Og dette er hvordan vi gjør det i selve C.
Slik at dette ikke bruker GetString og getchar funksjoner
som vi brukte fra CS50 biblioteket.
Vi kommer til å gjøre dette problemet i et par måter
slik at du kan se to forskjellige måter å gjøre det.
Både fread funksjon som Daniel nevnt og fgetc er gode måter å gjøre det.
Jeg tror fgetc er litt enklere, fordi den bare har, som du ser,
ett argument, FILE * at vi prøver å lese tegn fra,
og returverdien er en int.
Og dette er litt forvirrende, ikke sant?
>> Fordi vi får en karakter, så hvorfor ikke denne avkastningen en røye?
Dere har noen ideer om hvorfor dette ikke kan returnere en røye?
[Missy svar, uforståelig] >> Ja. Så Missy er helt rett.
Hvis det er ASCII, så dette heltall kunne kartlegges til en faktisk røye.
Kan være et ASCII-tegn, og det er riktig.
Det er akkurat det som skjer.
Vi bruker en int rett og slett fordi den har flere biter.
Det er større enn en røye, vår røye bare har 8 bits, som en byte på våre 32-bits maskiner.
Og en int har alle fire byte igjen av plass.
Og det viser seg at veien fgetc fungerer,
hvis vi bla nedover i synopsis vår i denne mannen siden litt,
bla helt ned. Det viser seg at de bruker denne spesielle verdi som kalles EOF.
Det er en spesiell konstant som returverdien av fgetc funksjon
når du treffer slutten av filen, eller hvis du får en feilmelding.
Og det viser seg at å gjøre disse sammenligningene med EOF riktig,
du vil ha det ekstra mengden av informasjon som du har i en int
motsetning til å bruke en char variabel.
Selv om fgetc er effektivt å få et tegn fra en fil,
du ønsker å huske på at det er tilbake noe som er av type int til deg.
Når det er sagt, det er ganske enkelt å bruke.
Det kommer til å gi oss en karakter, så alt vi trenger å gjøre er å spørre filen,
"Gi meg det neste tegnet, gi meg det neste tegnet, gi meg det neste tegnet,"
før vi kommer til slutten av filen.
Og som vil trekke i ett tegn om gangen fra fil vår,
og da kan vi gjøre hva vi vil med den.
Vi kan lagre det, kan vi legge det til en streng, kan vi skrive den ut.
Gjøre noe av det.
>> Zoome ut igjen og går tilbake til vår kategori C program,
hvis vi kommer til å bruke fgetc,
hvordan kan vi nærmer oss denne neste linje av koden?
Vi kommer til å bruke - fread vil gjøre noe litt annerledes.
Og denne gangen, vi bare kommer til å bruke fgetc å få ett tegn om gangen.
Å behandle en hel fil, kan hva vi har å gjøre?
Hvor mange tegn er det i en fil?
Det er mye. Så du sannsynligvis vil få en
og deretter få en annen og få en annen og få en annen.
Hva slags algoritme tror du vi kan ha til å bruke her?
Hva slags -? [Alexander] A for loop? >> Nettopp.
Noen type loop.
En for løkke er faktisk stor, i dette tilfellet.
Og som du sa, det høres ut som du vil ha en sløyfe over hele filen,
få et tegn om gangen.
Noen forslag på hva som kan se ut?
[Alexander, uforståelig]
>> Ok, bare fortell meg på engelsk hva du prøver å gjøre? [Alexander, uforståelig]
Så i dette tilfellet, det høres ut som vi prøver bare å sløyfe over hele filen.
[Alexander] Så I > Størrelsen -?
Jeg antar størrelsen på filen, ikke sant? Størrelsen - vi vil bare skrive det slik.
Størrelsen på filen for tiden, i + +.
Så det viser seg at den måten du gjør dette ved hjelp av fgetc, og dette er nytt,
er at det er ingen enkel måte å bare få størrelsen på en fil
med denne "sizeof" type konstruere som du har sett før.
Når vi bruker det fgetc funksjon, kan vi innføre en slags
Nye tøffe syntaks til dette for loop, der i stedet for å bruke bare en grunnleggende teller
å gå tegn for tegn, vi kommer til å trekke ett tegn om gangen,
ett tegn om gangen, og måten vi vet vi er på slutten
er ikke når vi har telt et visst antall tegn,
men når karakteren vi trekke ut er at spesiell slutten av filen karakter.
Så vi kan gjøre dette ved å - Jeg kaller dette lm, og vi kommer til å initialisere den
med vår første samtale for å få det første tegnet ut av filen.
Så denne delen her, dette kommer til å få en karakter ut av filen
og lagre den i variabelen lm.
Vi kommer til å fortsette å gjøre dette før vi kommer til slutten av filen,
som vi gjør ved testing for tegnet ikke er lik den spesielle EOF karakter.
Og da i stedet for å gjøre lm + +, noe som ville bare øke verdien,
så hvis vi lese en A ut av filen, en hovedstad A, sier
ch + + ville gi oss b, og da ville vi få c og deretter d.
Det er åpenbart ikke det vi ønsker. Hva vi vil her
i denne siste biten vi ønsker å få det neste tegnet fra filen.
>> Så hvordan kan vi få det neste tegnet fra filen?
Hvordan får vi det første tegnet fra filen?
[Student] fgetfile? >> Fgetc, eller, beklager, du var helt rett.
Jeg stavet feil det der. Så ja.
Her i stedet for å gjøre lm + +,
vi bare kommer til å ringe fgetc (fil) igjen
og lagre resultatet i vår samme lm variabel.
[Student spørsmål, uforståelig]
>> Det er der disse fil * gutta er spesielle.
Måten de arbeider er de - når du først åpne - når du først gjør det fopen anrop,
FILE * serverer effektivt som en peker til begynnelsen av filen.
Og deretter hver gang du ringer fgetc, beveger det ett tegn gjennom filen.
Så når du ringer dette, er du økes filpekeren av et tegn.
Og når du fgetc igjen, du flytter den en annen karakter
og en annen karakter og en annen karakter og en annen karakter.
[Student spørsmål, uforståelig] >> Og that - Ja.
Det er slags av denne magiske under panseret.
Du må bare holde økes gjennom.
På dette punktet, er du i stand til å faktisk jobbe med en karakter.
Så hvordan kan vi skrive ut dette til skjermen, nå?
Vi kan bruke samme printf ting som vi brukte før.
At vi har brukt hele semesteret.
Vi kan kalle printf,
og vi kan passere i karakter akkurat sånn.
En annen måte å gjøre det er stedet for å bruke printf og måtte gjøre dette formatet streng,
Vi kan også bruke en av de andre funksjonene.
Vi kan bruke fputc, som skriver et tegn på skjermen,
bortsett fra hvis vi ser på fputc - la meg zoome ut litt.
Vi ser hva som er hyggelig er det tar i karakteren som vi leser ut ved hjelp fgetc,
men da må vi gi det en bekk å skrive ut.
Vi kan også bruke putchar funksjonen, som vil sette direkte til standard ut.
Så det er en hel haug med forskjellige alternativer som vi kan bruke for utskrift.
De er alle i standard I / O-bibliotek.
Når du vil skrive ut - så printf, som standard, vil skrive ut til den spesielle standard ut strømmen,
som er at stdout.
Så vi kan bare referere til det som en slags denne magiske verdi, stdout her.
Oops. Sett semikolon utenfor.
>> Dette er en mye ny, funky informasjon her.
Mye av dette er svært idiomatisk, i den forstand at dette er koden
som er skrevet på denne måten bare fordi det er rent for å lese, lett å lese.
Det er mange forskjellige måter å gjøre det, mange forskjellige funksjoner du kan bruke,
men vi har en tendens til å bare følge de samme mønstrene om og om igjen.
Så ikke bli overrasket om du ser kode som dette kommer opp igjen og igjen.
OK. På dette punktet, må vi bryte for dagen.
Takk for at du kom. Takk for å se om du er online. Og vi vil se deg neste uke.
[CS50.TV]