[Powered by Google Translate] [DEEL 5: minder comfortabel]
[Nate Hardison, Harvard University]
[Dit is CS50.] [CS50.TV]
Dus welkom terug, jongens.
Welkom bij hoofdstuk 5.
Op dit punt, hebben voltooid quiz 0 en hebben gezien hoe je dat gedaan hebt,
hopelijk voel je echt goed, want ik was erg onder de indruk van de scores in deze sectie.
Voor onze online kijkers, we hebben een paar vragen
over de laatste twee problemen op het probleem set - of op de quiz, in plaats van.
Dus we gaan om te gaan over die heel snel, zodat iedereen ziet wat er gebeurd is
en hoe om te gaan door de werkelijke oplossing in plaats van alleen die de oplossing zelf.
We gaan gaan over de laatste paar problemen heel snel, 32 en 33.
Gewoon, weer, zodat dat de online kijkers zien.
>> Als u om uw probleem op 32, dat op pagina 13,
13 van de 16, probleem 32 is alles over swaps.
Het was allemaal om te ruilen twee gehele getallen.
Het is het probleem dat we gegaan over een paar keer in college.
En hier, wat we vroegen u om te doen is een snelle herinnering spoor.
Het invullen van de waarden van de variabelen zoals ze op de stapel
als de code gaat door deze swap functie.
In het bijzonder, wat we zoeken bij - Ik ga naar deze iPad neer te zetten -
in het bijzonder, wat we zoeken naar is deze lijn genummerd hier 6 rechts.
En het is genummerd 6 voor slechts contiguïteit met het vorige probleem.
Wat wij willen doen is weer te geven of het etiket van de toestand van het geheugen
omdat het op het moment dat we voeren deze lijn nummer 6,
dat is in feite een terugkeer van onze swap functie hier.
Als we naar beneden scrollen hier, zagen we dat de adressen van alles in het geheugen was beschikbaar voor ons.
Dit is erg belangrijk, we komen terug om het in slechts een moment.
En dan hier beneden op de bodem, we hadden een klein geheugen diagram dat we gaan om te verwijzen naar.
Ik heb eigenlijk dit gedaan op mijn iPad.
Dus ik ga heen en weer schakelen tussen de iPad en deze code alleen voor referentie.
>> Laten we beginnen. Ten eerste, laten we focussen op de eerste paar regels van de belangrijkste hier.
Om te beginnen, we gaan naar x te initialiseren op 1 en y 2.
We hebben dus twee integer variabelen, ze beiden zullen worden geplaatst op de stapel.
We gaan een 1 en een 2 in hen.
Dus als ik meer dan flip naar mijn iPad, hopelijk, laten we eens kijken -
Apple TV mirroring, en daar gaan we. Oke.
Dus als ik meer dan flip op mijn iPad,
Ik wil x initialiseren op 1 en y 2.
Dat doen we gewoon door het schrijven van een 1 in het vak x
en een 2 in het vak y. Vrij eenvoudig.
Dus laten we nu terug gaan naar de laptop, zien wat er gebeurt.
Dus dit volgende regel wordt het pas echt lastig.
We passeren het adres van x en het adres van y als de parameters a en b om de swap-functie.
Het adres van x en het adres van y zijn dingen die we niet kunnen berekenen
zonder te verwijzen naar deze bullet points recht naar beneden hier.
En gelukkig, de eerste twee bullet points ons precies vertellen wat de antwoorden zijn.
Het adres van x in geheugen 10, en het adres van y in geheugen 14.
Dus dat zijn de waarden die krijgen in doorgegeven als a en b tot boven in onze swap functie.
Dus nogmaals, terugschakelen naar ons diagram, kan ik schrijf een 10 in een
en 14 in b.
Nu, dit is het punt waar we verder gaan met de swap.
Dus flipping terug naar de laptop weer,
zien we dat de manier waarop de swap werkt is ik voor het eerst dereference een en sla het resultaat op in tmp.
Dus de dereference operator zegt: "He. Behandel de inhoud van variabele a als een adres.
Ga naar wat er opgeslagen is op dat adres, en laad het. "
Wat je uit te laden van de variabele zal worden opgeslagen in onze tmp variabele.
Flipping terug naar de iPad.
Als we naar 10 te pakken, weten we dat adres 10 is de varible x
want we werden verteld door onze opsommingsteken dat het adres van x in het geheugen is 10.
Dus we kunnen er naartoe te gaan, krijgen de waarde ervan, dat is 1, zoals we zien op onze iPad,
en laden die in tmp.
Ook dit is niet de uiteindelijke inhoud.
We gaan wandelen door en wij zullen onze uiteindelijke toestand van het programma te krijgen aan het eind.
Maar op dit moment hebben we de waarde 1 opgeslagen in tmp.
>> En er is een snelle vraag hier.
[Alexander] Is de dereference operator - dat is gewoon de ster vlak voor de variabele?
>> Ja. Dus de dereference operator, zoals we back flip naar onze laptop weer,
is deze ster recht tegenover.
In die zin is het - je het contrasteren met de operator voor vermenigvuldigen
die vereist dat twee dingen: de dereference operator is een unaire operator.
Slechts toegepast op een waarde in plaats van een binaire operator,
waar van toepassing op twee verschillende waarden.
Dus dat is wat er gebeurt in deze lijn.
We geladen de waarde 1 en opgeslagen in onze tijdelijke integer variabele.
De volgende regel, slaan we de inhoud van B in -
of beter gezegd, slaan we de inhoud die b wijst om in de plaats waar een wijst naar.
Als we analyseren deze van rechts naar links, gaan we dereference b,
gaan we tot en met 14 aan te pakken, gaan we het gehele getal dat er te grijpen,
en dan gaan we naar het adres 10,
en we gaan het resultaat van onze dereference van b te gooien in die ruimte.
Flipping terug naar onze iPad, waar kunnen we dit een beetje meer concreet,
het zou helpen als ik hier schrijf nummers op alle adressen.
Dus we weten dat op y, we zijn op het adres 14, x is op het adres 10.
Als we beginnen bij b, we dereference b, gaan we de waarde 2 te grijpen.
We gaan deze waarde te grijpen, want dat is de waarde die woont op het adres 14.
En we gaan om het in de variabele die woont op het adres 10,
die is daar, overeenkomend met onze variabele x.
Dus we kunnen doen een beetje overschrijven hier
waar we ons bevrijden van onze 1 en in plaats daarvan schrijven we een 2.
Dus is alles goed en wel in de wereld, ook al hebben we overschreven x nu heb.
Wij hebben opgeslagen oude waarde x in onze tmp variabele.
Dus we kunnen voltooien de swap met de volgende regel.
Flipping terug naar onze laptop.
Nu alles wat overblijft is om de inhoud te nemen uit onze tijdelijke integer variabele
en bewaar ze in de variabele die woont op het adres dat b houdt.
Dus we gaan om effectief dereference b om toegang te krijgen tot de variabele
dat op het adres dat b houdt in,
en we gaan naar de waarde die tmp houdt in dat spul.
Flipping terug naar de iPad eens te meer.
Ik kan wissen deze waarde hier, 2,
en in plaats daarvan zullen we kopiëren de 1 erin.
Dan is de volgende regel die wordt uitgevoerd, natuurlijk -
Als we terug bladeren naar de laptop - is dit punt 6,
dat is het punt waarop we wilden ons diagram volledig ingevuld.
Dus flipping terug naar de iPad nog een keer, zodat je kunt zien dat de ingevulde diagram,
kun je zien dat we een 10 in een, een 14 in b, een 1 op tmp, een 2 in x, en een 1 in y hebben.
Zijn er nog vragen over?
Betekent dit meer zin, die liep door het?
Maken minder zin? Hopelijk niet. Oke.
>> Pointers zijn een zeer lastig onderwerp.
Een van de jongens werken we met een veel voorkomende gezegde:
"Om pointers begrijpen, moet je eerst begrijpen pointers."
Waarvan ik denk dat is zeer waar. Het vergt wel een tijdje om te wennen.
Tekening veel foto's, zijn loting van het geheugen diagrammen zoals deze zeer behulpzaam,
en na je wandeling door voorbeeld na voorbeeld na voorbeeld,
het zal beginnen om een ​​beetje meer verstand en een beetje meer verstand en een beetje meer zin te maken.
Tot slot, op een dag, dan heb je het al helemaal onder de knie.
Hebt u vragen voordat we verder gaan naar het volgende probleem? Oke.
Dus back flip naar de laptop.
Het volgende probleem dat we hebben is probleem nummer 33 op file I / O.
Zoom in op deze een beetje.
Probleem 33 - Ja?
>> [Daniel] Ik had net een snelle vraag. Deze ster, of het sterretje,
het heet dereferentie wanneer u een sterretje voor.
Hoe heet het als je de ampersand voor?
>> De ampersand is voor de adres-van operator.
Dus laten we naar boven terug.
Oeps. Ik ben in de zoommodus, dus ik kan niet echt scroll.
Als we kijken naar deze code heel snel hier,
weer hetzelfde gebeuren.
Als we kijken naar deze code hier, op deze lijn waar we de oproep om te ruilen,
het en-teken is alleen maar te zeggen "get het adres waar de variabele x leven."
Wanneer uw compiler compileren van de code,
het moet fysiek markeren een plaats in het geheugen voor al uw variabelen te leven.
En de compiler dus wat kan dan doen als het eenmaal is samengesteld alles,
het weet, "Oh, ik x zet op het adres 10. Ik zet y op het adres 14."
Het kan dan invullen van deze waarden voor u.
Dus je kan dan - het kan dan gaan deze in en pas & y in ook.
Deze jongens krijgen het adres, maar ook, wanneer je langs ze in de swap-functie,
dit soort informatie, dit int * hier, vertelt de compiler,
"Oke, we gaan te interpreteren dit adres als een adres van een integer variabele."
Als adres van een int, die verschilt van het adres van een variabelenamen
omdat een int neemt, op een 32-bits machine, neemt 4 bytes ruimte,
terwijl een karakter neemt slechts 1 byte van de ruimte.
Dus het is belangrijk om te weten ook wat er - wat er leeft, wat voor soort waarde
woont op het adres dat werd doorgegeven inch
Of het adres dat u te maken hebt.
Op die manier weet je hoeveel bytes aan informatie om daadwerkelijk uit te laden van uw RAM-geheugen.
En dan, ja, werden deze dereference operator, zoals u vraagt,
gaat en toegang informatie op een bepaald adres.
Dus staat hier deze variabele de inhoud van een behandeling als een adres,
ga naar dat adres, en trek, te laden in de processor, lading in een register
de werkelijke waarden of de inhoud die leven op dat adres.
Nog meer vragen? Dit zijn goede vragen.
Het is een hoop nieuwe terminologie ook.
Het is ook een soort van funky, zien & en * op verschillende plaatsen.
>> Oke.
Dus terug naar probleem 33, file I / O.
Dit was een van die problemen die ik denk dat een paar dingen gebeurd.
Een, het is een vrij nieuw onderwerp.
Het werd al snel voorgelegd aan de quiz,
en dan denk ik het was een beetje als een van die woord problemen in de wiskunde
waar ze geven je veel informatie, maar je eigenlijk niet eindigen met een ton van het te gebruiken.
Het eerste deel van dit probleem is het beschrijven van wat een CSV-bestand is.
Nu, een CSV-bestand, volgens de beschrijving, is een door komma's gescheiden waarden bestand.
De reden dat deze zijn te allen interessant, en de reden waarom je ooit gebruiken,
is, omdat, hoeveel van jullie ooit gebruikte spullen zoals Excel?
Figuur meeste van jullie hebben, waarschijnlijk, of zullen gebruiken, op een bepaald punt in je leven.
U gebruikt iets als Excel.
Om de gegevens op te halen uit een Excel-spreadsheet of doe een soort van verwerking met het,
als je wilde een C-programma of Python programma, Java-programma te schrijven,
om te gaan met de gegevens die u hebt opgeslagen in daar,
een van de meest voorkomende manieren om hem eruit te halen is in een CSV-bestand.
En u kunt openen in Excel en als je naar de 'Opslaan als' dialoog,
je kunt krijgen uit een echte CSV-bestand.
>> Handig om te weten hoe om te gaan met deze dingen.
De manier waarop het werkt is dat het lijkt op een - ik bedoel, het is in wezen het nabootsen van een spreadsheet,
waar, zoals we hier zien, in het meest linkse stuk,
hebben we alle laatste namen.
Dus we hebben Malan, vervolgens Hardison, en dan Bowden, MacWilliam en Chan.
Alle achternaam. En dan een komma scheidt de laatste namen van de eerste namen.
David, Nate, Rob, Tommy, en Zamyla.
Ik heb altijd mengen Robby en Tom.
En dan, tot slot, de derde kolom is de e-mailadressen.
Als je eenmaal begrijpt dat de rest van het programma is vrij eenvoudig te implementeren.
Wat we hebben gedaan om deze dezelfde structuur na te bootsen in onze C-programma
wordt hebben we gebruik gemaakt van een structuur.
We beginnen te spelen met deze een beetje meer ook.
We zagen ze voor het eerst iets in probleem set 3, toen we te maken hadden met de woordenboeken.
Maar dit personeel struct slaat een achternaam, een voornaam en een e-mail.
Net als onze CSV-bestand is op te slaan.
Dus dit is gewoon omzetten van het ene formaat naar het andere.
We moeten, omzetten in dit geval een personeelslid struct in een lijn,
een door komma's gescheiden lijn, net als dat.
Is dat logisch? Jullie hebben alle genomen quiz,
dus ik me voorstellen dat je op zijn minst even de tijd om na te denken over deze had.
>> In de huur-functie, het probleem vraagt ​​ons om te genieten van - we zullen inzoomen op deze een beetje -
te nemen aan een staf structuur, een staf struct, met naam s,
en voeg de inhoud van onze staff.csv bestand.
Het blijkt dat dit vrij eenvoudig te gebruiken.
We soort van spelen met deze functies een beetje meer vandaag.
Maar in dit geval, de fprintf functie echt de sleutel.
Dus met fprintf, kunnen we afdrukken, net zoals jullie zijn printf dit hele term gebruikt.
U kunt printf een lijn naar een bestand.
Dus in plaats van alleen het maken van de gebruikelijke printf aan te roepen waar je het de format string
en dan het vervangen van alle variabelen met de volgende argumenten,
met fprintf, je allereerste argument is in plaats daarvan het bestand dat u wilt schrijven.
Als we op dit kijken in het apparaat, bijvoorbeeld, man fprintf,
kunnen we het verschil zien tussen printf en fprintf.
Ik zal inzoomen hier een beetje.
Dus met printf, we geven het een format string, en dan de volgende argumenten
zijn alle variabelen voor vervanging of substitutie in ons format string.
Overwegende dat het met fprintf, het eerste argument is inderdaad dit bestand * heet een stroom.
>> Moving terug naar hier om onze huur,
We hebben al onze bestanden * stroom voor ons geopend.
Dat is wat deze eerste regel doet, het opent de staff.csv bestand,
het opent het in append mode, en alles wat over is voor ons om te doen is
schrijf de personele organisatie aan het bestand.
En, laten we eens kijken, wil ik de iPad gebruiken?
Ik zal gebruik maken van de iPad. We hebben leegte - laten we dit op tafel te zetten, dus ik kan een beetje beter schrijven -
vervallen huur en het duurt in een argument, een staf structuur genaamd s.
Heb je onze bretels, hebben we ons bestand * de naam bestand,
we hebben onze fopen lijn aan ons gegeven,
en Ik zal gewoon schrijf het uit als puntjes omdat het al in de pedia.
En dan op onze volgende regel, we gaan om te bellen naar fprintf
en we gaan door te geven in het bestand dat we willen afdrukken,
en dan onze format string, die -
Ik laat jullie me vertellen hoe het eruit ziet.
En jij, Stella? Weet je wat het eerste deel van de format string eruit ziet?
[Stella] Ik weet het niet zeker. >> Voel je vrij om Jimmy te vragen.
Weet je, Jimmy?
[Jimmy] Zou het gewoon mee? Ik weet het niet. Ik ben niet helemaal zeker.
>> Oke. Wat dacht je van, heeft iemand je dit juist op het examen?
Nee, Oke.
Het blijkt dat hier alles wat we hoeven te doen is willen we elk deel van ons personeel structuur
worden afgedrukt als een string in ons bestand.
We gebruiken de string substitutie karakter drie verschillende tijden, want we hebben een achternaam
gevolgd door een komma, dan is een voornaam gevolgd door een komma,
en tenslotte het emailadres wordt gevolgd - die niet
monteren op mijn scherm - maar het is gevolgd door een newline karakter.
Dus ik ga het schrijven gewoon daar beneden.
En dan na onze format string,
hoeven we alleen maar de substituties, die we toegang krijgen tot het gebruik van de dot-notatie
dat we zagen in probleem set 3.
We kunnen gebruik maken s.last, s.first, en s.email
te vervangen in die drie waarden in onze format string.
Dus hoe ging dat? Logisch?
Ja? Nee? Mogelijk? Oke.
>> Het laatste ding dat we doen nadat we gedrukt en nadat we openden we onze file:
wanneer we een bestand geopend, we hebben altijd aan te denken om te sluiten.
Want anders zullen we uiteindelijk lekt het geheugen,
met maximaal file descriptors.
Dus om te sluiten, welke functie gebruiken we? Daniel?
[Daniel] fclose? >> Fclose, precies.
Het laatste deel van dit probleem was goed sluit het bestand met de fclose functie
die ziet er net als dat.
Niet te gek.
Cool.
Dus dat is probleem 33 op de quiz.
We zullen zeker meer file I / O komen.
We zullen een beetje meer te doen in lezing vandaag, of in artikel vandaag,
want dat is wat er gaat het grootste deel van deze aankomende PSET vormen.
Laten doorstromen van de quiz op dit punt. Ja?
>> [Charlotte]] Waarom fclose (bestand) in plaats van fclose (staff.csv)?
>> Ah. Omdat blijkt dat - dus de vraag, dat is een grote,
is de reden waarom, als we fclose schrijven, schrijven we fclose (bestand) ster variabele
in tegenstelling tot de bestandsnaam, staff.csv? Is dat juist? Ja.
Dus laten we eens een kijkje nemen. Als ik overschakel naar mijn laptop,
en laten we kijken naar de fclose functie.
Dus de fclose functie sluit een beek en het duurt in de pointer naar de stroom die we willen sluiten,
in tegenstelling tot de werkelijke bestandsnaam die we willen sluiten.
En dit is omdat achter de schermen, wanneer u een oproep wil doen aan fopen,
bij het openen van een bestand, bent u eigenlijk het toewijzen van geheugen aan informatie over het bestand op te slaan.
Dus je hebt bestands pointer met informatie over het bestand,
zoals het is geopend, de grootte, waar u op dit moment in het bestand,
zodat u kunt lezen en schrijven oproepen naar die bepaalde plaats in het bestand.
Je uiteindelijk het sluiten van de wijzer in plaats van het sluiten van de bestandsnaam.
>> Ja? [Daniel] Dus om huren te gebruiken, zou je zeggen - hoe het te krijgen van de input van de gebruiker?
Heeft fprintf handelen als GetString in de zin dat het gewoon wacht op de invoer van de gebruiker
en wordt u gevraagd dit type - of wachten tot je deze drie dingen typen?
Of heb je nodig om iets te gebruiken om huren te implementeren?
>> Ja. Dus we zijn niet - de vraag is, hoe krijgen we de input van de gebruiker
met het oog op verhuur implementeren? En wat we hier hebben is de beller van huur,
doorgegeven in dit personeel struct met alle gegevens die zijn opgeslagen in de struct reeds.
Dus fprintf is in staat om gewoon rechtstreeks schrijven dat de gegevens naar het bestand.
Er is geen wachttijd voor invoer van de gebruiker.
De gebruiker is al gegeven de input door goed om het in dit personeel struct.
En dingen, natuurlijk, zou breken als een van deze pointers waren null,
dus we schuiven een back-up hier en we kijken naar onze struct.
We hebben snaar laatste, string first, string e-mail.
We weten nu dat al die echt, onder de motorkap, zijn char * variabelen.
Die al dan niet wijzen naar nul.
Zij kunnen verwijzen naar geheugen op de heap,
misschien geheugen op de stack.
We weten niet echt, maar als een van deze pointers zijn null, of ongeldig,
dat die zeker zullen crashen onze verhuur functie.
Dat was iets dat soort was buiten het bereik van het examen.
We zijn niet zorgen te maken over dat.
Geweldig. Oke. Dus bewegen op uit de quiz.
>> Laten we sluiten deze man, en we gaan kijken naar PSET 4.
Dus als jullie kijken naar de PSET spec, zodra u het kunt openen, cs50.net/quizzes,
we gaan om te gaan door een paar van de sectie problemen van vandaag.
Ik ben naar beneden te scrollen - sectie van vragen begint op de derde pagina van de PSET spec.
En het eerste deel wordt u gevraagd om te gaan en de korte bekijken op heroriëntatie en leidingen.
Dat was een beetje een koele korte, toont u een aantal nieuwe, coole opdrachtregel trucs die u kunt gebruiken.
En dan hebben we een paar vragen voor u als goed.
Deze eerste vraag over stromen, waarop printf schrijft standaard,
we soort van aangeroerd gewoon een beetje een moment geleden.
Dit fprintf dat we gewoon hadden het over gaat in een bestand * stroom als argument.
fclose neemt in een bestand * stroom als goed,
en de return waarde van fopen geeft u een bestand * stroom ook.
De reden dat we niet hebben gezien degenen, die vóór als we behandeld printf
komt omdat printf heeft een standaard stroom.
En de standaard stroom waaraan zij schrijft
u zult te weten komen over de korte.
Dus zeker een kijkje nemen op het.
>> In paragraaf van vandaag, gaan we een beetje praten over GDB,
want hoe meer vertrouwd bent met het, de meer oefening krijg je met het,
hoe beter je zult daadwerkelijk jagen bugs in uw eigen code.
Dit versnelt het proces van het debuggen up enorm.
Dus met behulp van printf, elke keer dat je dat doet moet je je code opnieuw compileren,
je moet opnieuw opstarten, soms moet je de printf oproep verplaatsen,
commentaar uit code, het duurt slechts een tijdje.
Ons doel is om te proberen en u te overtuigen dat met GDB, je in wezen kan
printf iets op elk punt in je code en je nooit zorgen te hercompileren.
Je hoeft nooit te starten en te raden waar te printf volgende te houden.
Het eerste ding om te doen is om deze lijn te kopiëren en de programmadeel-aanduiding uitstappen van het web.
Ik ben het kopiëren van deze regel code die zegt: "wget ​​http://cdn.cs50.net".
Ik ga om het te kopiëren.
Ik ga dan naar mijn toestel, uitzoomen zodat u kunt zien wat ik doe,
plakken daar, en toen ik op Enter raakte, dit wget commando letterlijk is krijg je een web.
Het gaat om pull-down dit bestand af van het internet,
en het gaat om het op te slaan in de huidige directory.
Nu, als ik toon mijn huidige directory kun je zien dat ik dit section5.zip bestand goed had daar.
De manier om te gaan met die vent is unzip het,
die u kunt doen in de command line, net als dit.
Section5.zip.
Dat zal het uit te pakken, maakt u de map voor mij,
opblazen van de inhoud, leg ze in daar.
Dus nu kan ik gaan in mijn sectie 5 directory met de opdracht cd.
Wis het scherm met behulp van duidelijk. Dus het scherm op.
Nu heb ik een mooie schone terminal om te gaan met.
>> Nu als ik een lijst van alle bestanden die ik zie in deze map,
zie je dat ik vier bestanden hebt: buggy1, buggy2, buggy3, en buggy4.
Ik heb ook de bijbehorende. C bestanden.
We gaan niet naar de. C-bestanden zien er voor nu.
In plaats daarvan, we gaan om ze te gebruiken wanneer we open GDB.
We hebben hielden ze rond, zodat we toegang tot de eigenlijke broncode wanneer we gebruik van GDB,
maar het doel van dit deel van de sectie is om te knutselen rond met GDB
en zie hoe we het kunnen gebruiken om erachter te komen wat er mis gaat met elk van deze vier buggy's.
Dus we gaan gewoon door de kamer heel snel,
en ik ga iemand vragen om een ​​van de buggy programma's te draaien,
en dan gaan we als groep door middel van GDB, en we zullen zien wat we kunnen doen om deze programma's vast te stellen,
of ten minste te bepalen wat er mis kan gaan in elk van hen.
Laten we hier beginnen met Daniel. Zal je buggy1? Laten we eens kijken wat er gebeurt.
[Daniel] Het zegt dat er een applicatie fout. >> Ja. Precies.
Dus als ik zonder buggy1, krijg ik een seg fout.
Op dit punt, ik kon gaan en open te stellen buggy1.c,
proberen erachter te komen wat er mis kan gaan,
maar een van de meest onaangename dingen over dit segment fout fout
is dat het je niet vertellen op welke lijn van het programma dingen eigenlijk ging het mis en brak.
Je soort moet kijken naar de code
en erachter te komen met behulp van gok en controleer of printf om te zien wat er fout gaat.
Een van de coolste dingen over GDB is dat het echt, echt gemakkelijk
te achterhalen van de lijn waarop uw programma crasht.
Het is absoluut de moeite waard om het te gebruiken, al was het maar voor.
Dus om op te starten GDB, typ ik GDB, en dan geef ik het het pad naar het uitvoerbare bestand dat ik wil uitvoeren.
Hier ben ik het typen gdb ./buggy1.
Druk op Enter. Geeft me al deze copyright informatie,
en hier beneden zie je deze lijn die zegt: "Het lezen van symbolen van / home /
jharvard/section5/buggy1. "
En als alles goed gaat, dan zie je het afdrukken van een bericht dat er als volgt uitziet.
Het zal legenda, het zal zeggen: "Ik ben symbolen lezen van uw uitvoerbaar bestand,"
en dan zal het over deze "done" bericht hier.
Als je ziet wat andere variant van deze, of zie je het niet kon vinden de symbolen
of iets dergelijks, wat dat betekent is dat je gewoon niet hebt uitvoerbare gecompileerd goed.
Als we programma's voor gebruik met GDB samen te stellen, moeten we die speciale-markering g te gebruiken,
en dat is gedaan door standaard als het samenstellen van je programma's, gewoon door te typen maken
of maak buggy of maak herstellen mag elk van deze.
Maar als je handmatig het compileren bent met Clang, dan zul je moeten gaan en dat-markering g bevatten.
>> Op dit punt, nu hebben we onze GDB prompt,
het is vrij eenvoudig om te draaien van het programma.
We kunnen ofwel typen lopen, of we kunnen gewoon typen r.
De meeste GDB commando's kunnen worden afgekort.
Meestal tot slechts een of een paar letters, dat is erg mooi.
Dus Saad, als je Type R en druk op Enter, wat gebeurt er?
[Saad] Ik heb SIGSEGV, segmentatie fout, en dan al die onwaarheden.
>> Ja.
Zoals we zien op het scherm op dit moment, en zoals Saad zei:
wanneer we run of r typen en druk op Enter, we nog steeds dezelfde seg fout.
Dus met behulp van GDB niet oplost ons probleem.
Maar het geeft ons wat abracadabra, en het blijkt dat dit gobbledygook
eigenlijk vertelt ons waar het gebeurt.
Om ontleden dit een beetje, dit eerste bit is de functie waarin alles gaat verkeerd.
Er is een __ strcmp_sse4_2, en het vertelt ons dat het er in dit bestand
riep sysdeps/i386, dit alles, weer, soort van een puinhoop - maar lijn 254.
Dat is een beetje moeilijk te ontleden aan. Meestal als je dit soort dingen,
dat betekent dat het is seg vastgelopen in een van de systeem bibliotheken.
Dus iets te maken met strcmp. Jullie hebben gezien strcmp eerder.
Niet te gek, maar betekent dit dat strcmp kapot is of dat er een probleem is met strcmp?
Wat denk je, Alexander?
[Alexander] Is dat - is 254 de lijn? En de - niet de binaire, maar het is niet hun plafonds,
en dan is er nog een andere taal voor elke functie. Is dat 254 in die functie, of -?
>> Het is lijn 254. Het lijkt erop dat in deze. S bestand, dus het is de montage-code waarschijnlijk.
>> Maar, ik denk dat het meer dringende zaak is, want we hebben gekregen een segment fout,
en het lijkt alsof het komt van de strcmp functie,
betekent dit, dan is dat strcmp gebroken?
Het moet niet, hopelijk. Dus alleen maar omdat je een segmentation fault
in een van de systeemfuncties, kenmerkend dat betekent dat je gewoon niet hebt genoemd correct.
De snelste ding om te doen om erachter te komen wat er eigenlijk aan de hand
als je iets geks als dit, te zien wanneer u een segment fout,
vooral als je een programma dat met behulp van meer dan alleen de belangrijkste,
is het gebruik van een backtrace.
I afkorting backtrace door het schrijven bt, in tegenstelling tot de volledige backtrace woord.
Maar Charlotte, wat gebeurt er als u typt bt en druk op Enter?
[Charlotte] Het laat me twee lijnen, lijn 0 en lijn 1.
>> Ja. Dus lijn 0 en lijn 1.
Dit zijn de werkelijke stack frames die op dat moment waren in het spel wanneer je programma crashte.
Vanaf het bovenste frame, frame 0, en naar de onderste, dat frame 1.
Onze bovenste frame is de strcmp frame.
U kunt denken aan dit als vergelijkbaar met dat probleem waar we waren gewoon te doen op de quiz met de wijzers,
waar we ruilen stack frame op de top van de belangrijkste stack frame,
en we hadden de variabelen die swap werd met behulp van op de top van de variabelen die centraal werd gebruikt.
Hier onze crash gebeurde in onze strcmp functie, die werd genoemd door onze belangrijkste functie,
en backtrace geeft ons niet alleen de functies waarin de dingen niet,
maar het is ook ons ​​te vertellen waar alles werd aangeroepen.
Dus als ik ga dan een beetje meer naar rechts,
kunnen we zien dat ja, we waren op lijn 254 van deze strcmp-sse4.s bestand.
Maar de oproep werd gedaan op buggy1.c, lijn 6.
Dus dat betekent dat we kunnen doen - is dat we kunnen gewoon gaan controleren en te zien wat er gaande was
op buggy1.c, lijn 6.
Nogmaals, er zijn een paar manieren om dit te doen. Een daarvan is om uit te sluiten van de GDB
of uw code te openen in een ander venster en kruisverwijzingen.
Dat is in en van zichzelf, is erg handig want nu als je op kantooruren
en je hebt een seg fout en uw TF vraagt ​​zich af waar alles brak,
kun je gewoon zeggen: "O, lijn 6. Ik weet niet wat er gaande is,
maar iets over lijn 6 wordt veroorzaakt door mijn programma te breken. "
De andere manier om het te doen is dat je kunt deze opdracht genaamd lijst in GDB.
U kunt ook afkorten met l.
Dus als we raken l, wij wat hier te krijgen?
We krijgen een hele hoop rare dingen.
Dit is de eigenlijke montage-code
dat in strcmp_sse4_2.
Dit ziet er soort van funky,
en de reden waarom we krijgen dit is omdat op dit moment,
GDB heeft ons in frame 0.
>> Dus wanneer we kijken naar variabelen, elke keer als we kijken naar de broncode,
zijn we op zoek naar de bron code die betrekking heeft op de stack frame we op dit moment zijn binnen
Dus om iets zinnigs te krijgen, moeten we
verhuizen naar een stack frame dat meer zin heeft.
In dit geval zou de belangrijkste stackframe een beetje meer zin
want dat was eigenlijk de code die we schreven.
Niet de strcmp code.
De manier waarop je kunt verplaatsen tussen de frames, in dit geval, want we hebben twee,
Er zijn 0 en 1,
je dat doet met de op en neer commando's.
Als ik omhoog een frame,
nu ben ik in de belangrijkste stack frame.
Ik kan naar beneden om terug te gaan naar waar ik was,
weer omhoog, weer naar beneden, en weer omhoog.
Als je ooit doen uw programma in GDB, je een crash krijgt, krijg je de backtrace,
en je ziet dat het in sommige bestand dat je niet weet wat er gaande is.
Je probeert lijst, is de code niet u bekend voorkomen,
een kijkje nemen op uw frames en erachter te komen waar je bent.
Je bent waarschijnlijk in de verkeerde stapel frame.
Of op zijn minst dat je in een stapel frame dat niet is er een die je echt kunt debuggen.
Nu we in de juiste stack frame, we zijn in de belangrijkste,
nu kunnen we gebruik maken van de lijst met commando om erachter te komen wat de lijn was.
En je ziet het, het drukken het voor ons hier.
Maar we kunnen hitlijst allemaal hetzelfde, en de lijst geeft ons deze mooie afdruk
van de werkelijke broncode die is aan de gang hier.
>> In het bijzonder, kunnen we kijken naar lijn 6.
We kunnen zien wat er aan de hand is.
En het lijkt erop dat we het maken van een string vergelijking
tussen de string "CS50 rocks" en argv [1].
Iets over dit werd crashen.
Dus Missy, heb je een mening over wat kan worden hier aan de hand?
[Missy] Ik weet niet waarom het crashen. >> Je weet niet waarom het crashen?
Jimmy, alle gedachten?
[Jimmy] Ik ben niet helemaal zeker, maar de laatste keer dat we gebruikten snaar te vergelijken,
of strcmp, hadden we net als drie verschillende gevallen onder.
We hadden geen ==, denk ik niet, denk dat goed in die eerste lijn.
In plaats daarvan werd gescheiden in drie en was == 0,
was <0, denk ik, en was> 0.
Dus misschien zoiets? >> Ja. Dus er is dit probleem
van doen we de vergelijking correct?
Stella? Elke gedachten?
[Stella] Ik weet het niet zeker. >> Niet zeker. Daniel? Gedachten? Oke.
Het blijkt wat er hier gebeurt is wanneer we liepen het programma
en we kregen het segment fout, toen u het programma voor de eerste keer, Daniel,
gaf je het dan command line argumenten?
[Daniel] Nee. >> Nee. In dat geval, wat is de waarde van argv [1]?
>> Er is geen waarde. >> Juist.
Nou, er is geen geschikt tekenreekswaarde.
Maar er is een bepaalde waarde. Wat is de waarde die wordt opgeslagen in?
>> Een vuilnis waarde? >> Het is ofwel een vuilnis waarde of, in dit geval,
het einde van de argv array wordt altijd beëindigd met null.
Dus wat er werkelijk werd opgeslagen in is null.
De andere manier om dit op te lossen, in plaats van denken dat het door middel van,
is om te proberen af ​​te drukken uit.
Dit is waar ik zei dat het gebruik van GDB groot is,
want je kunt uitprinten alle variabelen, alle waarden die u wilt
met behulp van deze handige dandy-p commando.
Dus als ik typ p en dan typ ik de waarde van een variabele of de naam van een variabele,
zeggen, argc, zie ik dat argc is 1.
Als ik wil afdrukken argv [0], kan ik dat doen, net als dat.
En, zoals we zagen, argv [0] is altijd de naam van uw programma,
altijd de naam van het uitvoerbare.
Hier zie je het is het volledige pad naam kreeg.
Ik kan ook uitprinten argv [1] en zie wat er gebeurt.
>> Hier kregen we dit soort mystieke waarde.
We hebben dit 0x0.
Vergeet niet bij het begin van de term toen we spraken over hexadecimale getallen?
Of dat kleine vraag aan het eind van PSET 0 over hoe tot 50 vertegenwoordigen in hex?
De manier waarop we schrijven hexadecimale getallen in CS, alleen maar om niet verwarren onszelf
met decimale getallen, is dat we hen altijd voorafgaan door 0x.
Dus dit voorvoegsel 0x altijd gewoon betekent interpreteren het volgende nummer als een hexadecimaal getal,
niet als een string, niet als een decimaal getal, niet als een binair getal.
Omdat het aantal 5-0 is een geldig nummer in hexadecimaal.
En het is een getal in decimale, 50.
Dus dit is gewoon hoe disambiguate we.
Dus 0x0 middelen hexadecimale 0, die ook decimaal 0, binaire 0.
Het is gewoon de waarde 0.
Het blijkt dat dit het null is eigenlijk, in het geheugen.
Null is gewoon 0.
Hier, het element opgeslagen bij argv [1] is null.
Dus we proberen om onze "CS50 rocks" string te vergelijken met een null-string.
Dus dereferentie null, proberen om dingen te openen op nul,
die zijn meestal gaan om een ​​soort van segmentatie fout of andere slechte dingen gebeuren veroorzaken.
En het blijkt dat strcmp niet controleert om te zien
of u bent geslaagd in een waarde die is null.
Integendeel, het gewoon doorgaat, probeert zijn ding doen,
en als het seg fouten, het seg fouten, en het is jouw probleem. Je moet naar het te repareren.
Heel snel, we zouden hoe dit probleem te verhelpen? Charlotte?
[Charlotte] U kunt controleren met behulp van of.
Dus als argv [1] null is, == 0, dan terug 1, of iets [onverstaanbaar].
>> Ja. Dus dat is een geweldige manier om het te doen, zoals we kunnen nagaan,
de waarde die we staan ​​op het punt om te gaan in strcmp, argv [1], is het null?
Als het null, dan kunnen we zeggen oke, af te breken.
>> Een meer voorkomende manier om dit te doen is het gebruik van de argc waarde.
U kunt hier zien in het begin van de belangrijkste,
we weggelaten die eerste test die we meestal doen als we gebruik maken van command line argumenten,
dat is om te testen of onze argc waarde is wat we verwachten.
In dit geval, we verwachten op zijn minst twee argumenten,
de naam van het programma plus een andere.
Omdat we op het punt om het tweede argument gebruiken hier.
Dus met een soort van test op voorhand, voor onze strcmp oproep
dat de tests al dan niet argv ten minste 2, zou ook hetzelfde doen soort dingen.
We kunnen zien of dat werkt door het uitvoeren van het programma opnieuw.
U kunt uw programma altijd opnieuw op te starten binnen GDB, dat is erg leuk.
U kunt lopen, en als je pas in argumenten aan uw programma,
passeert u ze in als u belt loopt, niet wanneer je opstart GDB.
Op die manier houdt u een beroep op uw programma met verschillende argumenten iedere keer.
Dus lopen, of weer, ik kan typen r, en laten we zien wat er gebeurt als we typen "hallo".
Het zal altijd vragen of u wilt opnieuw beginnen vanaf het begin.
Meestal wil je het weer vanaf het begin.
En op dit punt, het opnieuw opstarten het weer, Het drukt
het programma dat we lopen, buggy1, met het argument hello,
en het drukt deze standaard uit, het zegt: "Je hebt een D te krijgen, 'verdrietig gezicht.
Maar we hebben niet seg fout. Het zei dat proces verlaten normaal.
Dus dat ziet er goed uit.
Nooit meer seg fout, we hebben het verleden,
zodat het lijkt alsof dat was inderdaad het segment fout bug die we kregen.
Helaas, het vertelt ons dat we een D. krijgt
>> We kunnen terug gaan en kijken naar de code en zien wat er gaande was er
om erachter te komen wat er was - waarom het ons te vertellen dat we een D. kregen
Laten we eens kijken, hier werd deze printf zeggen dat je een D. kreeg
Als we typen lijst, zoals u blijven typen lijst, het houdt itereren naar beneden door uw programma,
dus het zal u tonen de eerste paar regels van uw programma.
Dan zal je de volgende paar regels, en de volgende stuk en het volgende stuk.
En het zal blijven proberen naar beneden te gaan.
En nu we krijgen aan "regelnummer 16 is buiten het bereik."
Omdat het slechts 15 regels.
Als je op dit punt en je af te vragen: "Wat moet ik doen?" kunt u gebruik maken van de opdracht help.
Gebruik dan helpen en het de naam van een commando te geven.
En je ziet het GDB geeft ons al dit soort dingen.
Het zegt: "Met geen argument, tien meer lijnen na of rond de vorige lijst staan.
Lijst - bevat de tien regels voor - "
Dus laten we proberen met behulp van de lijst minus.
En dat geeft de 10 regels vorige, je kunt spelen met de lijst een beetje.
U kunt de lijst, lijst te doen -, kunt u zelfs geven de lijst een nummer, zoals lijst 8,
en het zal een lijst van de 10 regels rond regel 8.
En je kunt zien wat er hier aan de hand is heb je een eenvoudig als anders.
Als u typt in CS50 rotsen, Het drukt "Je een A. te krijgen"
Anders drukt "Je hebt een D. te krijgen"
Bummer stad. Oke. Ja?
>> [Daniel] Dus toen ik probeerde te doen CS50 rotsen zonder de aanhalingstekens,
het zegt "Je hebt een D. te krijgen"
Ik moest de citaten te krijgen om te werken, waarom is dat?
>> Ja. Het blijkt dat wanneer - dit is een andere leuke kleine versnapering -
wanneer u het programma uit te voeren, als we lopen en we typen CS50 rotsen,
net zoals Daniël zei hij dat deed, en je druk op Enter,
er staat nog steeds krijgen we een D.
En de vraag is, waarom is dit?
En het blijkt dat zowel onze terminal en GDB ontleden ze als twee gescheiden argumenten.
Want als er een ruimte, dat is impliciet als
het eerste argument beëindigd; het volgende argument gaat beginnen.
De manier om die te combineren tot twee, of sorry, tot een argument,
is het gebruik van de aanhalingstekens.
Dus nu, als we het in citaten en opnieuw opstarten, krijgen we een A.
Dus gewoon om samen te vatten, worden er geen aanhalingstekens, CS50 en rotsen geparsed als twee afzonderlijke argumenten.
Met citaten, het is geparsed als een argument zijn.
>> We zien dit met een breekpunt.
Tot nu toe hebben we gelopen ons programma, en het is gelopen
totdat het met seg gebreken of hits een fout
of totdat het verlaten en alle was helemaal goed.
Dit is niet per se de meest behulpzame ding, want soms
je hebt een fout in het programma, maar het is niet het veroorzaken van een segmentation fault.
Het is niet het veroorzaken van uw programma te stoppen of iets dergelijks.
De manier om GDB te krijgen om te pauzeren uw programma op een bepaald punt
is het instellen van een breekpunt.
U kunt dit doen door het instellen van een breekpunt op een functienaam
of u kunt een breekpunt op een bepaalde regel code.
Ik wil breekpunten op functienamen te stellen, omdat - gemakkelijk te onthouden,
en als je echt naar binnen en je broncode een beetje te veranderen,
dan is uw breekpunt daadwerkelijk zal blijven op dezelfde plaats in de code.
Overwegende dat, indien u gebruik maakt van regelnummers en de regelnummers te wijzigen
omdat je toevoegen of verwijderen of andere code, dan is uw breekpunten zijn allemaal helemaal verpest.
Een van de meest voorkomende dingen die ik doe is ingesteld een breekpunt op de belangrijkste functie.
Vaak zal ik starten GDB, ik typ b main, druk op Enter, en dat zal een breekpunt
op de belangrijkste functie die gewoon zegt: "Pauzeer het programma zodra u begint te lopen,"
en op die manier, als ik mijn programma uit te voeren met, zeg, CS50 rotsen als twee argumenten
en druk op Enter, het wordt de belangrijkste functie en deze stopt namelijk direct bij de eerste lijn,
vlak voor het evalueert de strcmp functie.
>> Omdat ik gepauzeerd, nu kan ik beginnen met uitmesten rond en zien wat er aan de hand
met alle verschillende variabelen die worden doorgegeven in mijn programma.
Hier kan ik printen argc en zie wat er gebeurt.
Zie dat argc is 3, omdat het 3 verschillende waarden in zit.
Het is de naam van het programma kreeg, het heeft het eerste argument en het tweede argument.
Wij kunnen die uit door te kijken naar argv [0], argv [1], en argv [2].
Dus nu zie je ook waarom dit strcmp oproep gaat mislukken,
omdat je ziet dat het was opgesplitst de CS50 en de rotsen in twee afzonderlijke argumenten.
Op dit punt, als je eenmaal hebt raakte een breekpunt, kunt u doorgaan om door uw programma
regel voor regel, in tegenstelling tot het starten van een programma opnieuw.
Dus als je niet wilt dat uw programma opnieuw te starten en gewoon door te gaan van hier,
kunt u gebruik maken van de continue commando en verder zal het programma uit te voeren tot het einde.
Net als zij heeft gedaan hier.
Echter, als ik het programma opnieuw starten, CS50 rotsen, het raakt mijn breekpunt weer,
en deze keer, als ik niet wil helemaal ga je gewoon door de rest van het programma,
Ik kan gebruik maken van de volgende opdracht, die ik ook afkorten met n.
En dit zal u door het programma regel voor regel.
Zodat u kunt kijken als dingen uit te voeren, als variabelen veranderen, als dingen bijgewerkt.
En dat is erg leuk.
Het andere koele ding is in plaats van het herhalen van dezelfde commando over en over en weer,
als je gewoon op Enter - dus even je ziet heb ik niet getypt in iets -
als ik gewoon op Enter drukt, wordt het te herhalen het vorige commando,
of de vorige GDB opdracht die ik net binnen
Ik kan blijven raken op Enter en het zal blijven doorlopen mijn code regel voor regel.
Ik roep jullie om uit te gaan bekijken van de andere buggy's ook.
We hebben geen tijd om door alle van hen vandaag in paragraaf.
De broncode is er, dus je kunt soort te zien wat er aan de hand
achter de schermen als je echt vast komt te zitten,
maar op zijn minst, maar de praktijk opstarten GDB,
het uitvoeren van het programma tot het breekt op u,
het verkrijgen van de backtrace, uitzoeken welke functie de crash was in,
welke lijn het was op, het afdrukken van een aantal variabele waarden,
maar dat je een gevoel te krijgen voor het, want dat zal je echt helpen voor de toekomst.
Op dit punt, gaan we hierna uit GDB, waarvan je gebruik te stoppen of gewoon q.
Als uw programma is in het midden van het runnen van nog, en het is niet verlaten,
het zal altijd vragen: "Ben je zeker dat je echt wilt stoppen?"
U kunt gewoon op ja.
>> Nu gaan we kijken naar de volgende probleem dat we hebben, dat is de kat programma.
Als je de korte op heroriëntatie en pijpen, zul je zien dat Tommy dit programma gebruikt
die wordt afgedrukt in principe de gehele output van een bestand naar het scherm.
Dus als ik kat lopen, dit is eigenlijk een ingebouwd programma om het apparaat,
en als je Macs kunt u dit ook doen op je Mac, als je open te stellen terminal.
En wij - kat, laten we zeggen, cp.c, en druk op Enter.
Wat dit deed, als we omhoog een beetje en zien waar we liepen de lijn,
of waar we de opdracht cat liep, het letterlijk net uitgeprint de inhoud van cp.c naar ons scherm.
We kunnen opnieuw opstarten en je kunt samen te stellen in meerdere bestanden.
Dus u kunt doen kat cp.c, en dan kunnen we ook samenvoegen van de Cat.C bestand,
dat is het programma dat we gaan schrijven,
en het zal terug print beide bestanden om terug te gaan naar ons scherm.
Dus als we naar boven een klein beetje, dan zien we dat als we liepen deze kat cp.c, Cat.C,
eerst afgedrukt van de cp-bestand, en dan eronder, het uitgeprint het Cat.C bestand recht naar beneden hier.
We gaan dit gebruiken om gewoon onze voeten nat.
Speel met eenvoudige afdruktaken naar de terminal, zien hoe dat werkt.
Als jullie openen met gedit Cat.C, druk op Enter,
zie je het programma dat we gaan schrijven.
We hebben deze mooie boiler plate inbegrepen, dus we hebben geen tijd te besteden typen dat alles uit.
We controleren ook het aantal doorgegeven argumenten inch
We printen een mooie gebruiksbericht.
>> Dit is het soort ding dat, opnieuw, alsof we het over,
het is bijna als spiergeheugen.
Vergeet niet om te blijven doen hetzelfde soort dingen
en altijd afdrukken van een soort van nuttige bericht
zodat mensen weten hoe je je programma uit te voeren.
Met kat, het is vrij eenvoudig, we gaan gewoon om te gaan door alle van de verschillende argumenten
die werden doorgegeven aan ons programma, en we gaan om af te drukken
de inhoud van het scherm een ​​voor een.
Om bestanden af ​​te drukken op het scherm, we gaan iets vergelijkbaars te doen
naar wat we deden op het einde van de quiz.
Aan het einde van de quiz, dat programma te huren, moesten we het openen van een bestand,
en dan moesten we afdrukken.
In dit geval gaan we het openen van een bestand, en we gaan in plaats daarvan lezen van.
Dan gaan we, af te drukken in plaats van naar een bestand, we gaan om af te drukken op het scherm.
Dus het afdrukken naar het scherm dat u alle eerder hebt gedaan met printf.
Dus dat is niet al te gek.
Maar het lezen van een bestand is een beetje raar.
We gaan door dat een beetje op een moment.
Als jullie terug gaan naar dat laatste probleem op uw quiz, probleem 33,
de eerste lijn die we gaan doen hier, het openen van het bestand, is zeer vergelijkbaar met wat we hebben gedaan daar.
Dus Stella, wat doet die lijn eruit, wanneer we een bestand te openen?
[Stella] Hoofdstad FILE *, bestand - >> Oke. >> - Is gelijk aan fopen. >> Yup.
Die in dit geval is? Het is in het commentaar.
>> Het is in de reactie achterlaten? argv [i] en r?
>> Precies. Goed zo. Dus Stella is helemaal goed.
Dit is wat de lijn eruit ziet.
We gaan naar een bestand stroom variabele te krijgen, op te slaan in een FILE *, dus alle kappen,
FILE, *, en de naam van deze variabele zal zijn dossier.
We kunnen noemen wat we willen. We kunnen noemen first_file of file_i, wat we zouden willen.
En dan de naam van het bestand werd in op de opdrachtregel naar dit programma.
Dus het is opgeslagen in argv [i,] en dan gaan we naar dit bestand te openen in de leesmodus.
Nu we het bestand geopend, wat is het ding dat we altijd aan te denken om te doen
wanneer we hebben een dossier geopend? Sluiten.
Dus Missy, hoe sluiten we een bestand?
[Missy] fclose (bestand) >> fclose (bestand). Precies.
Geweldig. Oke. Als we kijken naar dit commentaar doen hier,
het zegt, "Open argv [i] en print de inhoud naar stdout."
>> Standaard out is een rare naam. Stdout is gewoon onze manier om te zeggen
we willen het afdrukken naar de terminal, we willen het afdrukken naar de standaard uitvoer stroom.
We kunnen eigenlijk te ontdoen van deze opmerking hier.
Ik ga om het te kopiëren en te plakken want dat is wat we deden.
Op dit punt, nu moeten we het bestand wat te lezen bij beetje.
We hebben gesproken over een aantal manieren om het lezen van bestanden.
Welke zijn je favorieten tot nu toe?
Welke manieren heb je gezien of weet je nog, om bestanden te lezen?
[Daniel] fread? >> Fread? Dus fread is een. Jimmy, weet u nog meer?
[Jimmy] Nee. >> Oke. Nope. Charlotte? Alexander? Elke anderen? Oke.
Dus de anderen zijn fgetc, is er een die we veel gebruiken.
Er is ook fscanf; jullie te zien een patroon hier?
Ze beginnen allemaal met f. Alles wat te maken heeft met een bestand.
Er is fread, fgetc, fscanf. Dit zijn alle functies lezen.
Voor het schrijven hebben we fwrite, we hebben fputc in plaats van fgetc.
We hebben ook fprintf zoals we zagen aan de quiz.
Aangezien dit een probleem betreft het lezen van een bestand,
we gaan naar een van deze drie functies te gebruiken.
We gaan niet om deze functies te gebruiken hier beneden.
Deze functies zijn allemaal te vinden in de standaard I / O library.
Dus als je kijkt naar de top van dit programma,
kun je zien dat we al de header-bestand voor de standaard I / O library inbegrepen.
Willen we erachter te komen welke we willen gebruiken,
kunnen we altijd het openstellen van de man-pagina's.
Dus we kunnen typen man stdio
en lees alles over de stdio input en output functies in C.
En we kunnen nu al zien oh, kijk. Het is fgetc vermelden, is het vermelden fputc.
Zo kunt u doorklikken een beetje en kijk naar, laten we zeggen, fgetc
en kijk naar de man pagina.
Je kunt zien dat het gaat samen met een hele hoop andere functies:
fgetc, fgets, getc, getchar, krijgt, ungetc, en de input van characters en strings.
Dus dit is hoe lezen we in characters en strings van bestanden van standaard invoer,
die hoofdzakelijk uit de gebruiker.
En dit is hoe we het doen in de werkelijke C.
Dus dit is niet met behulp van de GetString en getchar functies
die we hebben gebruikt uit de CS50 bibliotheek.
We gaan dit probleem te doen in een paar manieren
zodat u kunt zien twee verschillende manieren om het te doen.
Zowel de fread functie die Daniel genoemd en fgetc zijn goede manieren om het te doen.
Ik denk dat fgetc is een beetje makkelijker, omdat het alleen heeft, zoals je ziet,
een argument, de FILE * dat we proberen om het karakter lezen,
en de geretourneerde waarde is een int.
En dit is een beetje verwarrend, toch?
>> Omdat we het krijgen van een personage, dus waarom niet deze terugkeer een char?
Jullie enig idee over waarom dit misschien niet terug een char?
[Missy antwoorden, onverstaanbaar] >> Ja. Dus Missy is helemaal goed.
Als het ASCII, dan integer, worden toegewezen aan een effectief char.
Kan een ASCII-teken zijn, en dat klopt.
Dat is precies wat er gebeurt.
We gebruiken een int simpelweg omdat er meer bits.
Het is groter dan een char; onze char alleen 8 bits, dat 1 byte op onze 32-bit machines.
En een int heeft alle 4 bytes ter waarde van de ruimte.
Het blijkt dat de manier fgetc werkt,
Als we naar beneden scrollen in onze samenvatting in deze man pagina een beetje,
scroll helemaal naar beneden. Het blijkt dat ze deze speciale waarde genaamd EOF te gebruiken.
Het is een speciale constante als de geretourneerde waarde van de functie fgetc
wanneer je de einde van het bestand, of als u een foutmelding krijgen.
En het blijkt dat om goed deze vergelijkingen maken met EOF,
u wilt dat de extra hoeveelheid informatie die je hebt hebben in een int
in tegenstelling tot het gebruik van een char variabele.
Hoewel fgetc wordt effectief het krijgen van een personage uit een bestand,
je wilt onthouden, dat het iets is dat van het type int is aan u terug.
Dat gezegd hebbende, het is vrij gemakkelijk te gebruiken.
Het zal ons een teken, dus alles wat we moeten doen is blijven vragen het bestand,
"Geef mij het volgende teken, geef me het volgende teken, geef me het volgende teken,"
tot we bij het einde van het bestand.
En dat zal trekken in een karakter per keer uit ons bestand,
en dan kunnen we doen wat we willen met het.
We kunnen het op te slaan, kunnen we toevoegen aan een string, kunnen we uitprinten.
Heeft een van die.
>> Zoomen weer uit en gaan terug naar onze Cat.C programma,
Als we gaan fgetc te gebruiken,
hoe kunnen wij dit volgende regel code?
We gaan in het gebruik - fread zal iets anders te doen.
En deze keer, we gewoon gaan fgetc te gebruiken om een ​​teken te krijgen op een moment.
Als u een volledige bestand te verwerken, kan wat we moeten doen?
Hoeveel tekens zijn er in een bestand?
Er zijn een heleboel. Dus wilt u waarschijnlijk een te krijgen
en krijgen dan nog een keer en ontvang een keer en ontvang een.
Wat voor soort algoritme denk je dat we zou kunnen hebben om hier te gebruiken?
Welk type -? [Alexander] Een for-lus? >> Precies.
Een soort van lus.
Een lus daadwerkelijk groot is in dit geval.
En zoals je zei, het klinkt alsof je een lus over het hele bestand,
om een ​​teken tegelijk.
Eventuele suggesties over hoe dat eruit zou kunnen zien?
[Alexander, onverstaanbaar]
>> Ok, vertel me in het Engels wat je probeert te doen? [Alexander, onverstaanbaar]
Dus in dit geval, het klinkt alsof we gewoon proberen om lus over het hele bestand.
[Alexander] Dus ik > De omvang van -?
Ik denk dat de grootte van het bestand, toch? De grootte - we zullen gewoon schrijven het zo.
Bestandsgrootte voorlopig, i + +.
Zo blijkt dat de manier waarop u dit doet met behulp van fgetc, en dit is nieuw,
is dat er geen gemakkelijke manier om gewoon de grootte van een bestand
met deze "sizeof" type constructie dat u eerder hebt gezien.
Als we dat fgetc functie te gebruiken, introduceren we een soort van
nieuwe, funky syntaxis van deze for-lus, waar in plaats van met slechts een basis teller
om teken voor teken te gaan, we gaan om een ​​teken te trekken op een moment,
een teken per keer, en de manier waarop we weten dat we aan het eind
wordt niet als we telden een bepaald aantal tekens,
maar als het personage dat we trek, is dat bijzonder einde van het bestand karakter.
Dus we kunnen dit doen door - ik noem dit l, en we gaan het initialiseren
met onze eerste oproep om het eerste teken te halen uit het bestand.
Dus dit deel hier, dit gaat om een ​​teken te krijgen uit het bestand
en opslaan in de variabele ch.
We gaan dit blijven doen tot we bij het einde van het bestand,
Dat doen we door het testen voor het karakter niet gelijk is aan die speciale EOF karakter.
En dan in plaats van het doen van l + +, zou dat net verhogen de waarde,
dus als we lezen een A uit het bestand, een hoofdletter A, zeg,
ch + + zou ons b, en dan zouden we krijgen c en daarna d.
Dat is duidelijk niet wat we willen. Wat we willen hier
in dit laatste stukje is willen we naar het volgende teken te krijgen uit het bestand.
>> Dus hoe kunnen we het volgende teken uit het bestand?
Hoe we het eerste teken te krijgen van het dossier?
[Student] fgetfile? >> Fgetc, of, sorry, je was helemaal gelijk.
Ik verkeerd gespeld het daar. Dus ja.
Hier in plaats van het doen van l + +,
We gaan gewoon naar fgetc (bestand) weer bellen
en sla het resultaat op in onze dezelfde l variabele.
[Student vraag, onverstaanbaar]
>> Dit is waar deze FILE * jongens zijn speciaal.
De manier waarop ze werken is dat ze - wanneer u voor het eerst opent - wanneer u voor het eerst maken dat fopen oproep,
de FILE * fungeert effectief als een pointer naar het begin van het bestand.
En dan elke keer als je belt fgetc, het beweegt een teken door het bestand.
Dus wanneer je dit noemen, je bent het verhogen van de bestands pointer met een teken.
En als je weer fgetc, je verplaatst een ander karakter
en een karakter en een ander karakter en een ander karakter.
[Student vraag, onverstaanbaar] >> En Dat is - ja.
Het is een soort van deze magische onder de motorkap.
Je gewoon blijven verhogen door.
Op dit punt, ben je in staat om daadwerkelijk te werken met een karakter.
Dus hoe kunnen we dit af te drukken op het scherm, nu?
We kunnen gebruik maken van dezelfde printf ding dat we eerder gebruikt.
Dat hebben we gebruik gemaakt van hele semester.
We kunnen printf bellen,
en we kunnen passeren in het teken net als dat.
Een andere manier om het te doen is in plaats van printf en met dit format string te doen,
kunnen we ook gebruik maken van een van de andere functies.
We kunnen gebruik maken fputc, die een karakter u op het scherm,
behalve als we kijken naar fputc - laat me uit te zoomen een beetje.
We zien wat er mooi is duurt het in het karakter dat we lezen met behulp van fgetc,
maar dan moeten we het eens stroom af te drukken op.
We kunnen ook gebruik maken van de putchar functie, die direct te maken aan standaard uit.
Dus er zijn een hele hoop verschillende opties die we kunnen gebruiken voor het afdrukken.
Ze zijn allemaal in de standaard I / O library.
Wanneer u wilt afdrukken - zo printf, standaard, zal afdrukken naar de speciale standaard uit beek,
en dat is dat stdout.
Dus we kunnen alleen maar verwijzen naar het als soort van deze magische waarde, stdout hier.
Oeps. Zet de puntkomma buiten.
>> Dit is een heleboel nieuwe, funky informatie hier.
Veel van deze zeer idiomatisch, in die zin dat dit code
dat is geschreven op deze manier alleen maar omdat het is schoon om te lezen, makkelijk te lezen.
Er zijn veel verschillende manieren om dit te doen, veel verschillende functies die u kunt gebruiken,
maar we hebben de neiging om gewoon dezelfde patronen volgen over en voorbij.
Wees dus niet verbaasd als je ziet code zoals deze komen opnieuw en opnieuw.
Oke. Op dit punt moeten we breken voor de dag.
Bedankt voor het komen. Bedankt voor het kijken als je online bent. En we zien jullie volgende week.
[CS50.TV]