[Powered by Google Translate] [SECȚIUNEA 5: mai puțin confortabilă]
[Nate Hardison, Universitatea Harvard]
[Acest lucru este CS50.] [CS50.TV]
Deci bun venit înapoi, băieți.
Bine ați venit la secțiunea 5.
În acest moment, au absolvit Quiz 0 si ce am vazut cum ai făcut,
sperăm că te simți cu adevărat bine pentru că am fost foarte impresionat de rezultatele din această secțiune.
Pentru telespectatorii noștri on-line, am avut o serie de întrebări
despre ultimele două probleme pe set de probleme - sau pe test, mai degrabă.
Deci, vom trece peste cele foarte repede, astfel încât toată lumea vede ceea ce sa întâmplat
și cum să treacă prin soluția reală, mai degrabă decât vizionează doar soluția în sine.
Vom trece peste ultimele doua probleme foarte repede, 32 și 33.
Doar, din nou, astfel încât telespectatorii pot vedea on-line asta.
>> Dacă îți vei opri la problema ta 32, care se află pe pagina 13,
13 din 16, problema 32 este totul despre swap-urilor.
A fost vorba de pompare două numere întregi.
Este problema cu care ne-am uitat peste de câteva ori în curs.
Și aici, ceea ce ne-au cerut să faci este o urmă de memorie rapidă.
Pentru a completa valorile variabilelor, acestea sunt pe stiva
ca codul trece prin această funcție de swap.
În special, ceea ce ne uitam la - Mă duc să afișezi această iPad jos -
în special, ceea ce căutăm la această linie este numerotată 6 chiar aici.
Și este numerotat 6 pentru doar contiguitate cu problema precedentă.
Ceea ce vrem să facem este afișa sau etichetează starea de memorie
cum este la momentul când am executa acest numar linia 6,
care este efectiv o întoarcere de la funcția de swap nostru chiar aici.
Dacă vom defila în jos aici, am văzut că adresele de tot în memorie au fost furnizate de pentru noi.
Acest lucru este foarte cheie, vom reveni la ea într-o clipă.
Și apoi aici, la partea de jos, am avut o diagramă de memorie mic care vom referi la.
Am făcut de fapt acest lucru pe iPad meu.
Așa că am de gând să alterneze înainte și înapoi între iPad și acest cod doar pentru referință.
>> Să începem. În primul rând, să ne concentrăm asupra primele linii ale principal de aici.
Pentru a începe, vom inițializa x și y la 1 la 2.
Deci avem doua variabile intregi, ei amândoi vor fi plasate pe stiva.
Vom pune un 1 și un 2 în ele.
Deci, dacă am inlocuit cu iPad meu, sper, să vedem -
Apple TV oglindire, și acolo vom merge. Bine.
Deci, dacă am inlocuit cu iPad meu,
Vreau să inițializeze x și y la 1 la 2.
Noi facem asta, pur și simplu de scris un 1 în caseta marcată x
și un 2 în caseta marcată y. Destul de simplu.
Deci, acum să ne întoarcem la laptop, să vedem ce se întâmplă în continuare.
Deci, această linie următor este în cazul în care lucrurile devin complicate.
Trecem adresa lui x și y adresa ca parametrii a și b pentru funcția de swap.
Adresa lui x și y adresa sunt lucruri pe care nu le putem calcula
fără a face referire la acestea glonț arată chiar aici.
Și din fericire, primele două puncte bullet ne spună exact ce răspunsurile sunt.
Adresa lui x în memoria este de 10, iar adresa de y în memoria este de 14.
Deci, acestea sunt valorile care se trecut în cât a și b până sus, în funcție de swap nostru.
Deci, din nou, trecerea inapoi la diagrama noastră, pot scrie un 10 într-un
și un 14 în B.
Acum, acest punct este în cazul în care vom continua cu swap.
Deci, flipping înapoi la laptop nou,
vedem că modul de swap de lucrări este că dereference mai întâi un magazin și rezultatul în tmp.
Deci, operatorul dereference spune, "Hei. Tratați conținutul variabilei o ca o adresă.
Du-te la tot ce este stocat la acea adresa, și încărcați-l. "
Ce poți încărca din variabila va fi stocat în variabila tmp nostru.
Răsturnarea înapoi la iPad.
Dacă mergem la adresa 10, știm că adresa 10 este x varible
pentru că ne-au spus de la punctul nostru de bullet că adresa lui x în memoria este de 10.
Deci putem merge acolo, pentru a primi valoarea de ea, care este de 1, așa cum vom vedea pe iPad nostru,
și încărcați că în tmp.
Din nou, acest lucru nu este conținutul finale.
Vom merge prin și vom ajunge la starea noastră finală a programului de la sfârșitul anului.
Dar acum, avem valoarea 1 stocată în tmp.
>> Și există o întrebare rapidă aici.
[Alexander] este operatorul dereference - asta e doar dreptul de stea în fața variabilei?
Da >>. Deci, operatorul dereference, așa cum ne întoarce la laptop-ul nostru din nou,
este această stea chiar în fața.
În acest sens, este - îl contrasteze cu operatorul de înmulțire
care necesită două lucruri; operatorul dereference este un operator unar.
Doar aplicată la o valoare, spre deosebire de un operator binar,
în cazul în care ați aplica pentru două valori diferite.
Deci, asta e ceea ce se întâmplă în această linie.
Am încărcat valoarea 1 și stocate în ea noastră variabila integer temporară.
Linia următoare, vom păstra conținutul de b în -
sau, mai degrabă, am stoca conținutul pe care b este în care indică locul în care se indică spre o.
Dacă analizăm acest lucru de la dreapta la stânga, vom b dereference,
vom aborda 14, vom apuca întreg care este acolo,
și apoi vom merge la adresa 10,
și am de gând să arunce rezultatul dereference nostru de b în acel spațiu.
Flipping înapoi la iPad nostru, unde putem face acest lucru un pic mai concret,
s-ar putea ajuta dacă am scrie numerele de pe toate adresele de aici.
Deci știm că la y, suntem la adresa 14, x este la adresa 10.
Când vom începe de la b, am dereference b, vom apuca valoarea 2.
Vom apuca această valoare pentru că este valoarea pe care o trăiește, la adresa 14.
Și vom pune în variabila care locuiește la adresa 10,
care este chiar acolo, corespondente x noastre variabile.
Astfel încât să putem face un pic de suprascrierea aici
în cazul în care vom scăpa de 1 noastră și în loc să ne scrie un 2.
Deci, totul e bine și frumos în lume, chiar dacă ne-am x adăugiri acum.
Ne-am păstrat vechea valoare x în variabila tmp nostru.
Deci, putem finaliza swap cu linia următoare.
Flipping înapoi la laptop-ul nostru.
Acum, tot ce rămâne de făcut este să ia conținutul din nostru variabila integer temporară
și le păstrează în variabila care locuiește la adresa pe care b este exploatație.
Deci, vom b dereference în mod eficient pentru a avea acces la variabila
că se află la adresa pe care b deține în ea,
și am de gând să umple valoarea pe care tmp ține în ea.
Răsturnarea înapoi la iPad o dată mai mult.
Eu pot șterge această valoare aici, 2,
și în loc vom copia dreapta 1 în ea.
Apoi următoarea linie care execută, desigur -
dacă ne întoarce la laptop - este asta punctul 6,
care este punctul de la care ne-am dorit să avem diagrama noastră complet completate.
Deci, flipping înapoi la iPad o dată mai mult, doar astfel încât să puteți vedea diagrama de completat,
puteți vedea că avem o 10 într-un, un tanar de 14 de b, 1 la tmp, un 2 în x, și un 1 în y.
Există întrebări despre acest lucru?
Are acest lucru face mai mult sens, după ce a umblat prin el?
Sens mai puțin? Să sperăm că nu. Bine.
>> Pointeri sunt un subiect foarte complicat.
Unul dintre tipii cu care lucrăm are un proverb foarte frecvente:
"Pentru a înțelege indicații, trebuie să înțelegem mai întâi indicii."
Care cred că este foarte adevărat. Ea nu ia un timp să se obișnuiască cu ea.
Tragere la sorți de imagini, tragerea la sorți de diagrame de memorie ca aceasta sunt foarte utile,
și după ce te plimbi prin exemplu, după exemplul după exemplu,
acesta va începe să aibă sens un pic mai mult și simt un pic mai mult și un pic mai mult sens.
În cele din urmă, într-o zi vei avea pe toate complet stăpânit.
Orice întrebări înainte de a trece la urmatoarea problema? Bine.
Deci, vă întoarce la laptop.
Următoarea problemă care o avem este problema numărul 33 pe fisierul I / O.
Mări pe acest bit un pic.
Problema 33 - Da?
>> [Daniel] Tocmai am avut o întrebare rapidă. Aceasta stea, sau asterisc,
se numește dereferencing atunci când utilizați un asterisc înainte.
Cum se numește atunci când utilizați ampersand înainte?
>> Ampersand înainte de a se adresa-de operator.
Deci, haideți să derulați înapoi.
Hopa. Sunt în modul zoom, asa ca nu pot cu adevărat de parcurgere.
Dacă ne uităm la acest cod foarte repede chiar aici,
din nou, același lucru se întâmplă.
Dacă ne uităm la acest cod chiar aici, pe această linie în cazul în care vom face apel la schimb,
ampersand spune doar "să se adresa la care trăiește variabile x."
Atunci când compilatorul compilează codul,
de fapt, trebuie să marcheze un loc fizic în memorie pentru toate variabilele dvs. pentru a trăi.
Și deci ce compilatorul poate face apoi după ce a fost compilat totul,
știe, "Oh, am pus x la adresa 10 mi-am pus y la adresa 14.".
Se poate umple apoi în aceste valori pentru tine.
Astfel încât să puteți apoi - se poate trece apoi acest lucru în trecere și & Y, precum și în.
Tipii ăștia obține adresa, dar ele, de asemenea, atunci când le trece în funcția de swap,
acest tip de informații, aceasta * int chiar aici, spune compilator,
"Bine, vom fi interpretarea această adresă ca adresă a unei variabile integer."
Ca o adresă a unui int, care este diferită de adresa unei variabile caracter
deoarece un int preia, pe o mașină de 32-biți, ocupă 4 octeți de spațiu,
întrucât un personaj doar preia 1 octet de spațiu.
Deci, este important să știți, de asemenea, ceea ce este - ceea ce trăiește, ce tip de valoare
locuiește la adresa care a fost trecut inch
Sau adresa pe care ai de a face cu.
În acest fel, știi câți octeți de informații pentru a încărca de fapt din RAM-ul.
Și apoi, da, acest operator dereference, ca tine au cerut,
merge și accesează informații la o anumită adresă.
Deci se spune, cu această variabilă o aici, să trateze conținutul unui drept o adresă,
du-te la acea adresă, și trageți afară, încărcați în procesor, sarcina într-un registru
valorile reale sau conținutul care locuiesc la acea adresă.
Orice mai multe întrebări? Acestea sunt întrebări bune.
E o mulțime de noi terminologii prea.
Este, de asemenea, un fel de funky, văzând & * și în locuri diferite.
>> Bine.
Deci, înapoi la problema 33, dosar I / O.
Aceasta a fost una dintre acele probleme pe care cred ca o pereche de lucruri sa întâmplat.
Unul, este un subiect destul de nou.
Acesta a fost prezentat destul de repede înainte de test,
și apoi cred că a fost un fel de una dintre aceste probleme sugerate în matematică
în cazul în care ei vă dau o mulțime de informații, dar de fapt nu se termina prin a avea de a utiliza o tona de ea.
Prima parte a acestei probleme este ceea ce descrie un fișier CSV este.
Acum, un fișier CSV, potrivit descrierii, este un valori separate prin virgulă dosar.
Motivul acestea sunt deloc interesante, si motivul pentru care ai folosi vreodată,
este, deoarece, câți dintre voi ați folosit vreodată chestii cum ar fi Excel?
Figura cea mai mare dintre voi au, probabil, sau va folosi la un moment dat în viața dumneavoastră.
Vei folosi ceva de genul Excel.
În scopul de a obține datele dintr-o foaie de calcul Excel sau de a face orice fel de prelucrare cu ea,
în cazul în care ai vrut să scrie un program C sau un program Python, Java programului,
a face cu datele stocate acolo,
una dintre cele mai comune modalități pentru a ieși este într-un fișier CSV.
Și vă puteți deschide Excel și atunci când te duci la "Save As" dialog,
poti scoate un fișier CSV real.
>> La îndemână pentru a ști cum să se ocupe cu aceste lucruri.
Modul în care funcționează este că e similar cu - Adică, e în esență imitandu-o foaie de calcul,
în cazul în care, după cum vom vedea aici, în piesă foarte cea mai din stânga,
avem toate numele de familie.
Deci avem Malan, apoi Hardison, și apoi Bowden, MacWilliam, și apoi Chan.
Toate numele de familie. Și apoi o virgulă separă numele de familie de la primele nume.
David, Nate, Rob, Tommy, și Zamyla.
Am amesteca mereu Robby și Tom.
Și apoi, în cele din urmă, a treia coloană este adresele de e-mail.
Odată ce ați înțeles că, restul programului este destul de simplu să pună în aplicare.
Ceea ce am făcut în scopul de a imita această structură aceeași în programul nostru C
este că am folosit o structură.
Vom începe să joci cu acestea un pic mai mult, de asemenea.
Noi le-am văzut pentru prima pic set de probleme 3, atunci când avem de-a face cu dicționare.
Dar acest struct personalului stochează un nume de familie, un nume în primul rând, și un e-mail.
La fel ca fișier CSV nostru a fost de depozitare.
Deci, aceasta este doar conversia de la un format la altul.
Avem de a converti, în acest caz, o struct personal într-o linie,
o linie separate prin virgulă, la fel ca asta.
Are vreun sens? Voi s-au luat toate test,
așa îmi imaginez ați avut cel puțin un timp să se gândească la asta.
>> În funcția de închiriere, problema ne cere să ne ia în - Vom mări pe acest bit un pic -
ia într-o structură de personal, o struct personal, cu numele lui,
și adăugați conținutul său la dosarul nostru staff.csv.
Se pare că acest lucru este destul de simplu de folosit.
Vom fel de joc cu aceste funcții un pic mai mult azi.
Dar în acest caz, funcția fprintf este într-adevăr cheia.
Deci, cu fprintf, putem imprima, la fel ca și voi ați fost folosind printf acest termen întreg.
Aveți posibilitatea să printf o linie într-un fișier.
Deci, în loc de a face doar în cazul în care apelul de obicei printf vă dau un format al șirului
și apoi înlocuiți toate variabilele cu următoarele argumente,
cu fprintf, argument prima ta este în locul fișierul pe care doriți să scrie.
Dacă ar fi să se uite la acest lucru în aparat, de exemplu, omule fprintf,
putem vedea diferența dintre printf și fprintf.
Voi mări aici un pic.
Deci, cu printf, ne dau un șir format, și apoi argumentele ulterioare
sunt toate variabilele de înlocuire sau substituire în șir format noastră.
Întrucât, cu fprintf, primul argument este într-adevăr acest fișier * numit un curs de apa.
>> Mutarea înapoi aici pentru a ne închiriere,
ne-am luat deja curs de apa noastră * dosarul deschis pentru noi.
Asta e ceea ce face această prima linie, se deschide fișierul staff.csv,
îl deschide în modul de adăugare, și tot ce a mai rămas pentru noi să facem este
scrie structura de personal la dosar.
Și, să vedem, nu vreau să folosesc iPad?
Voi folosi iPad. Avem anulate - Să punem asta pe masă, așa că am să scriu un pic mai bine -
anula închiriere și este nevoie de un singur argument în, o structura de personal numit uri.
Ai bretele noastre, ne-am luat nostru * fișier numit fișier,
avem linia noastra de fopen ne-a dat,
și eu voi scrie doar ca puncte din moment ce este deja în Pedia.
Și apoi pe linia următoarea noastră, vom face un apel la fprintf
și vom trece în fișierul pe care dorim să imprimați,
și apoi șirul formatului nostru, care -
Te las să-mi spuneți voi cum arată.
Cum despre tine, Stella? Știi ce prima parte a format-șir arata ca?
[Stella] Eu nu sunt sigur. >> Nu ezitați să întrebați pe Jimmy.
Știi, Jimmy?
[Jimmy] Ar fi doar ultima? Nu știu. Eu nu sunt în totalitate sigur.
Bine >>. Ce zici, a spus nimeni obține acest corecta asupra examen?
Nu regulă.
Se pare că aici tot ce trebuie să faceți este să ne dorim fiecare parte a structurii personalului nostru
care urmează să fie imprimate ca un șir de caractere în fișier nostru.
Noi folosim doar substituirea de caractere aleatoare de trei ori diferite, pentru că avem un nume de familie
urmat de virgulă, apoi un nume urmat de o virgulă,
și apoi în cele din urmă adresa de email care este urmat - care nu este
montarea pe ecranul meu - dar este urmat de un caracter linie noua.
Așa că am de gând să-l scrie doar acolo.
Și în urma apoi șirul formatului nostru,
avem doar inlocuiri, pe care le accesați folosind notația punct
pe care am văzut-o în setul de probleme 3.
Putem folosi s.last, s.first, și s.email
să substituie în aceste trei valori în șir formatul nostru.
Deci, cum a mers? Asigurați-simț?
Da? Nu? Posibil? Bine.
>> Ultimul lucru pe care o facem după ce ne-am imprimat și după ce am deschis fișierul nostru:
ori de câte ori am deschis un fișier, noi întotdeauna trebuie să vă amintiți să-l închidă.
Pentru că altfel vom ajunge scurgeri de memorie,
folosind până descriptori de fișiere.
Deci, pentru a se închide, pe care funcția nu folosim? Daniel?
[Daniel] fclose? Fclose >>, exact.
Deci, ultima parte a acestei probleme a fost în mod corespunzător închide fișierul, folosind funcția fclose,
care arată ca asta.
Nu prea nebun.
Mișto.
Deci, asta e problema 33 privind testul.
Vom avea cu siguranta mai mult fisier I / O, vine.
Vom face un pic mai mult în curs de astăzi, sau în secțiunea de astăzi,
pentru că asta e ceea ce se întâmplă pentru a forma cea mai mare parte a acestei PSET viitoare.
Să trecem de la testul de la acest punct. Da?
>> [Charlotte]] De ce fclose (fișier) în loc de fclose (staff.csv)?
Ah >>. Pentru că se pare că - așa întrebare, care este unul mare,
de aceea, atunci când scriem fclose, suntem scris fclose (fisier) este variabilă Stele
spre deosebire de numele de fișier, staff.csv? Este corect? Da.
Deci, haideți să aruncăm o privire. Dacă aș reveni la laptop-ul meu,
și să ne uităm la funcția fclose.
Deci, funcția fclose închide un curs de apa si-l ia în pointer la fluxul pe care ne-o dorim pentru a închide,
spre deosebire de numele de fișier real pe care ne-o dorim pentru a închide.
Și aceasta se datorează faptului că în spatele scenei, atunci când face un apel la fopen,
atunci când deschideți un fișier, sunteți de fapt, alocarea de memorie pentru a stoca informații despre fișier.
Deci, aveți indicatorul fișier care conține informații despre fișier,
cum ar fi e deschis, dimensiunea acesteia, în cazul în care vă aflați în prezent în dosar,
astfel încât să puteți face citirea si scrierea apeluri la acel loc special în fișierul.
Ajungi închiderea indicatorul în loc de închiderea numele fișierului.
>> Da? [Daniel] Deci, în scopul de a utiliza închiriere, ați spune - cum se obține datele introduse de utilizator?
Acționează ca fprintf getString în sensul că va aștepta doar pentru datele introduse de utilizator
și vă rog să introduceți acest lucru - sau să așteptați pentru tine de a introduce aceste trei lucruri în?
Sau aveți nevoie pentru a folosi ceva pentru a pune în aplicare închiriat?
Da >>. Deci nu suntem - întrebarea a fost, cum ajungem introduse de utilizator
, în scopul de a pune în aplicare închiriat? Și ceea ce avem aici este apelantului de închiriere,
a trecut în acest struct personal cu toate datele stocate în struct deja.
Deci, fprintf este capabil de a scrie doar că datele direct la fișierul.
Nu e nici o așteptare pentru introduse de utilizator.
Utilizatorul a dat deja introduse de către acesta în mod corespunzător punerea în acest struct personal.
Și lucrurile, bineînțeles, s-ar rupe dacă oricare dintre aceste indicii au fost nule,
asa ca am derula înapoi aici și ne uităm la struct nostru.
Avem șir șir trecut, în primul rând, e-mail șir.
Acum știm că toți cei care într-adevăr, sub capota, sunt variabile char *.
Care poate sau nu poate fi îndreptată la zero.
Ele pot fi zone de memorie pe heap,
Poate că de memorie pe stiva.
Noi nu știm cu adevărat, dar în cazul în care oricare dintre aceste indicii sunt nule, sau nevalabile,
că va prăbuși cu siguranță funcția noastră de închiriere.
Asta a fost ceva care a fost un fel de dincolo de domeniul de aplicare al examenului.
Noi nu suntem griji despre asta.
Mare. Bine. Deci, trecerea de la testul.
>> Să închidem acest tip, și ne vom uita la PSET 4.
Deci, dacă voi uita la spec. PSET, odată ce îl puteți accesa, cs50.net/quizzes,
am de gând să treacă printr-o câteva dintre problemele actuale secțiunea.
Mă derulând în jos - secțiunea de întrebări începe la pagina a treia a spec. PSET.
Și prima parte vă solicită să meargă și să urmăriți scurt reorientare și conducte.
Care a fost un fel de scurtă rece, prezinta cateva trucuri noi, interesante din linia de comandă pe care le puteți utiliza.
Și apoi avem câteva întrebări pentru tine, de asemenea.
Această primă întrebare despre fluxuri, la care printf scrie în mod implicit,
am un fel de atins pe doar un pic acum un moment.
Acest fprintf că am fost doar discutăm ia într-o curs de apa * fișier ca argument.
fclose ia într-o curs de apa * fișier, precum și,
și valoarea returnată de funcția fopen vă oferă un flux de fișier *, de asemenea.
Motivul pentru care nu am văzut pe cei înainte atunci când ne-am ocupat cu printf
se datorează faptului că are printf un flux prestabilit.
Și implicit fluxul de la care se scrie
veți afla despre în scurt.
Deci, să ia cu siguranta o privire la ea.
>> În secțiunea de astăzi, vom vorbi un pic despre GDB,
deoarece mai familiar ești cu ea, practica mai mult te cu ea,
mai în măsură veți fi de fapt în jos pentru a vâna bug-uri din propriul cod.
Acest proces accelereaza de depanare la extrem.
Deci, prin utilizarea printf, de fiecare dată când face asta va trebui să recompilați codul,
trebuie să-l rulați din nou, uneori, va trebui să mutați în jurul valorii de apel printf,
comentați cod, este nevoie de doar un timp.
Scopul nostru este de a încerca și vă convingă că cu GDB, în esență, puteți
printf ceva în orice punct din codul dvs. și nu va mai trebui să-l recompilați.
Niciodată nu trebuie să înceapă și să păstreze ghicitul unde să printf următoare.
Primul lucru de făcut este de a copia această linie și să obțină codul sectiune off a web.
Sunt copierea această linie de cod care spune, "http://cdn.cs50.net wget".
Am de gând să-l copiați.
Am de gând să merg pe la aparatul meu, zoom out astfel încât să puteți vedea ce fac,
lipirea-l acolo, si cand l-am lovit Enter, aceasta comanda wget literalmente este un web obține.
Se va trage în jos acest fișier de pe Internet,
și o să-l salvați în directorul curent.
Acum, dacă am lista mea de directorul curent, puteți vedea că am luat acest fișier section5.zip chiar acolo.
Mod de a face cu tipul ăla este să-l dezarhivați,
pe care le puteți face în linia de comandă, la fel ca asta.
Section5.zip.
Asta va dezarhivati, creați folderul pentru mine,
umfla tot conținutul, le-a pus acolo.
Asa ca acum pot merge în mea secțiunea 5 director folosind comanda cd.
Goliți ecran utilizând clar. Deci, clar ecranul.
Acum am luat un terminal de frumos curat pentru a face față.
>> Acum, dacă am lista cu toate fișierele care văd în acest director,
vezi ca am patru fișiere: buggy1, buggy2, buggy3, și buggy4.
Am, de asemenea, fișierele lor corespunzătoare. C..
Noi nu te vom uita la fișierele. C timp de acum.
În schimb, am de gând să le folosească atunci când ne deschidem GDB.
Le-am păstrat în jurul valorii de astfel încât să avem acces la codul sursă reală atunci când suntem utilizați GDB,
dar scopul acestei părți a secțiunii este să se joace în jurul valorii de cu GDB
și să vedem cum putem folosi pentru a afla ce se întâmplă în neregulă cu fiecare dintre aceste programe buggy patru.
Deci, suntem doar de gând să în jurul valorii de camera foarte repede,
și am de gând să întreb pe cineva pentru a rula unul dintre programele buggy,
și apoi vom merge ca un grup prin GDB, și vom vedea ce putem face pentru a remedia aceste programe,
sau cel puțin a identifica ce se întâmplă greșit în fiecare dintre ele.
Să începem aici cu Daniel. Va rula buggy1? Să vedem ce se întâmplă.
[Daniel] Se spune că e un defect cerere. Da >>. Exact.
Deci, dacă am alerga buggy1, I a lua o defecțiune seg.
În acest moment, am putea merge și deschide buggy1.c,
încercați și dau seama ce se întâmplă greșit,
dar unul dintre lucrurile cele mai enervante despre această eroare vina seg
este că nu-ți spun pe ce linie a programului de fapt, lucrurile au mers prost și rupt.
Ai cam trebui să se uite la codul
și dau seama de utilizarea presupunere și să verificați sau printf pentru a vedea ce se întâmplă greșit.
Unul dintre cele mai cool lucruri despre GDB este că e foarte, foarte usor
să dau seama linia de la care se blochează de program.
E cu totul merită să-l folosească, chiar dacă doar pentru asta.
Deci, pentru a boot-up GDB, tip I GDB, iar apoi am da drumul la executabil pe care vreau să fug.
Aici am tastarea gdb ./buggy1.
Apăsați Enter. Dă-mi toate aceste informații de copyright,
și aici veți vedea această linie care spune, "simboluri citirea de pe / home /
jharvard/section5/buggy1. "
Și dacă totul merge bine, vei vedea imprima un mesaj care arata ca acest lucru.
Va citi simboluri, acesta va spune "Eu citesc simboluri din fișierul executabil dumneavoastră,"
și apoi va avea această "făcut" mesajul aici.
Dacă vedeți unele variații alte de acest lucru, sau dacă vezi că nu a putut găsi simbolurile
sau ceva de genul asta, ceea ce înseamnă că este faptul că pur și simplu nu s-au compilat executabil dumneavoastră în mod corespunzător.
Când ne-am compila programe pentru utilizarea cu GDB, trebuie să ne folosim de pavilion special care-g,
și că a făcut în mod implicit, dacă compila programele, doar prin tastarea face
sau de a face sau de a face buggy recupera, oricare dintre cele.
Dar dacă sunteți compilați manual cu zăngănit, atunci va trebui să mergi și să includă faptul că-g pavilion.
>> În acest moment, acum că ne-am nostru GDB prompte,
e destul de simplu pentru a rula programul.
Am posibilitatea să tastați, fie a alerga, sau putem chiar tip R.
Cele mai multe comenzi GDB poate fi trunchiat.
De obicei, la doar una sau câteva litere, care este destul de frumos.
Deci Saad, dacă tastați r și apăsați Enter, ce se întâmplă?
[Saad] Am SIGSEGV, eroare de segmentare, și apoi toată această bolboroseală.
Da >>.
Ca ne vedem pe ecran chiar acum, și la fel ca Saad a spus,
atunci când am tip rula sau R și apăsați Enter, vom obține în continuare vina segmentul aceeași.
Deci, folosind GDB nu rezolvă problema noastră.
Dar ea ne dă ceva neinteligibil, și se pare că această bolboroseală
de fapt, ne spune în cazul în care se întâmplă.
Pentru a analiza acest bit un pic, acest bit este primul funcția în care totul se întâmplă greșit.
Nu e __ strcmp_sse4_2, și ne spune că aceasta se întâmplă în acest fișier
numit sysdeps/i386, toate acestea, din nou, un fel de mizerie - dar linia 254.
Asta e un fel de greu de analizat. De obicei, când vezi chestii de genul asta,
ceea ce înseamnă că este SEG Faulting într-una dintre bibliotecile de sistem.
Deci, ceva de-a face cu strcmp. Voi ați văzut strcmp înainte.
Nu prea nebun, dar acest lucru înseamnă că strcmp este rupt sau că există o problemă cu strcmp?
Ce crezi, Alexander?
[Alexander] E - 254 este linia? Și - nu binar, dar nu e plafoanele lor,
și apoi există o altă limbă pentru fiecare funcție. Este faptul că 254 din această funcție, sau -?
>> E linia 254. Se pare ca in acest dosar. Lui, așa că de cod de asamblare, probabil.
>> Dar, cred că lucrul mult mai presant este, pentru că am ajuns o defecțiune seg,
si se pare ca vine de la funcția strcmp,
face acest lucru implică, atunci, că strcmp este spart?
Acesta nu ar trebui, să sperăm. Deci, doar pentru că aveți o eroare de segmentare
într-una din funcțiile de sistem, de obicei, asta înseamnă că tu nu l-au numit în mod corect.
Cel mai rapid lucru de făcut pentru a descoperi ce se întâmplă de fapt pe
când vezi ceva nebunesc ca asta, ori de câte ori veți vedea un defect seg,
mai ales dacă aveți un program care folosește mai mult decât principal,
este de a utiliza un backtrace.
Am abrevierea backtrace de scris bt, spre deosebire de cuvântul backtrace completă.
Dar Charlotte, ce se întâmplă când introduceți BT și apăsați Enter?
[Charlotte] Ea îmi arată două linii, 0 linie și linia 1.
Da >>. Deci, linia 0 si linia 1.
Acestea sunt cadrele reale stivei, care au fost în prezent în joc, atunci când programul sa prăbușit.
Pornind de la cel mai de sus rama, cadru 0, și merge la partea de jos mai-, care este cadrul 1.
Cadru noastră cea mai de sus este cadru strcmp.
Vă puteți gândi la acest lucru ca la această problemă similară am fost doar faci pe testul cu pointerii,
în cazul în care ne-am schimba rama teancul în partea de sus a cadrului stivă principal,
si am avut variabilele care a fost de swap utilizând pe partea de sus a variabilelor care principalul a fost folosind.
Aici accident noastră sa întâmplat în funcția noastră strcmp, care a fost numit de către funcția nostru principal,
și backtrace este oferindu-ne nu numai funcțiile în care lucrurile eșuat,
dar este, de asemenea, ne spune în cazul în care totul a fost sunat din.
Deci, dacă am parcurge peste un pic mai la dreapta,
putem vedea că da, am fost pe linia 254 din acest fisier strcmp-sse4.s.
Dar apelul a fost făcut la buggy1.c, linia 6.
Asta înseamnă că putem face - este putem merge doar verifica afară și a vedea ce se întâmplă pe
la buggy1.c, linia 6.
Din nou, există două moduri de a face acest lucru. Una este de a ieși din GDB
sau au codul deschide în altă fereastră și referință încrucișată.
Faptul că, în sine, este destul de la îndemână pentru că acum, dacă ești la ore de birou
și le-ați luat un defect segment si TF dumneavoastră se întreabă unde totul a fost de rupere,
vă pot spune doar, "Oh, linia 6. Nu știu ce se întâmplă,
dar ceva despre linia de 6 este cauza programul meu pentru a rupe. "
Un alt mod de a face acest lucru este ca poti folosi aceasta comanda numita listă în GDB.
Puteți, de asemenea, cu abrevierea L.
Deci, dacă ne-am lovit eu, ce am ajuns aici?
Avem o grămadă de chestii ciudate.
Acesta este codul de asamblare real
care este în strcmp_sse4_2.
Acest lucru arată un fel de funky,
și motivul pentru care suntem obtinerea acest lucru este pentru că acum,
GDB noi are în cadru 0.
>> Deci, oricând ne uităm la variabile, orice moment ne uităm la codul sursă,
ne uitam la codul sursă care se referă la cadrul de stiva suntem în prezent inch
Deci, în scopul de a obține ceva semnificativ, trebuie să ne
a trece la un cadru stivă care face mai mult sens.
În acest caz, cadrul principal de stivă ar avea sens un pic mai mult,
pentru că a fost de fapt codul pe care am scris.
Nu strcmp codul.
Modul în care se pot deplasa între cadre, în acest caz, pentru că avem două,
avem 0 și 1,
faci asta cu sus și în jos comenzi.
Dacă aș muta în sus un cadru,
acum eu sunt în cadrul stivă principal.
Pot să vă deplasa în jos pentru a merge înapoi de unde am fost,
du-te din nou, du-te jos din nou, și du-te din nou.
Dacă veți face vreodată programul dumneavoastră în GDB, veți obține un accident, te backtrace,
și veți vedea că este în unele fișier pe care nu știi ce se întâmplă.
Ai încercat listă, codul nu arata familiar pentru tine,
să ia o privire la cadre de dvs. și dau seama unde te afli.
Esti, probabil, în cadrul stivă greșit.
Sau, cel puțin ești într-un cadru stivă care nu este una care se poate depana cu adevarat.
Acum că suntem în cadrul stivă caz, suntem în principal,
acum putem folosi comanda listă să dau seama ce a fost linia.
Și puteți să-l vedeți, îl tipărite pentru noi chiar aici.
Dar putem lovi lista toate la fel, și lista ne dă această imprimare frumos
din codul sursă reală ce se intampla pe aici.
>> În special, ne putem uita la linia 6.
Putem vedea ce se întâmplă pe aici.
Si se pare ca facem o comparație șir
între șirul de caractere "CS50 roci" și argv [1].
Ceva despre acest lucru a fost crashing.
Deci Missy, nu aveți gânduri cu privire la ce s-ar putea intampla aici?
[Missy] Nu stiu de ce se crashing. Tu >> Nu stiu de ce e crashing?
Jimmy, orice fel de gânduri?
[Jimmy] Eu nu sunt în totalitate sigur, dar ultima dată când am folosit string compara,
sau strcmp, am avut trei cazuri diferite, la fel ca în cadrul acestuia.
Noi nu am avut un ==, nu cred că, chiar în acea prima linie.
În schimb, a fost separat în trei, iar unul a fost == 0,
unul a fost <0, cred, și unul a fost> 0.
Deci, poate ceva de genul asta? Da >>. Deci, există această problemă
din facem comparația corect?
Stella? Orice gânduri?
[Stella] Eu nu sunt sigur. >> Nu sunt sigur. Daniel? Gânduri? Bine.
Se pare că ceea ce se întâmplă aici este atunci când am fugit programului
și ne-am vina seg, atunci când a fugit programul pentru prima dată, Daniel,
i-ai da orice argumente de linie de comandă?
[Daniel] Nr >> Nr În acest caz, ceea ce este valoarea de argv [1]?
>> Nu există nici o valoare. Corect >>.
Ei bine, nu există nici o valoare șir corespunzătoare.
Dar există o anumită valoare. Care este valoarea pe care se depoziteaza acolo?
O valoare >> gunoi? >> E fie o valoare de gunoi sau, în acest caz,
sfârșitul matrice argv este întotdeauna terminat cu null.
Deci, ceea ce de fapt a fost stocat acolo este nulă.
Alt mod de a rezolva acest lucru, mai degrabă decât gândindu-se că prin,
este să încercați să-l imprimați.
Acest lucru este în cazul în care spuneam că folosind GDB este mare,
deoarece aveți posibilitatea să imprimați toate variabilele, toate valorile pe care doriți
folosirea acestui îndemână dandy-comanda p.
Deci, dacă am tastați p și apoi am tastați valoarea unei variabile sau numele unei variabile,
spun, argc, văd că argc este 1.
Dacă vreau să imprime argv [0], pot face acest lucru la fel ca asta.
Și cum am văzut, argv [0] este întotdeauna numele programului,
întotdeauna numele executabilului.
Aici vei vedea că are numele calea completă.
Eu pot imprima de asemenea, argv [1] și a vedea ce se întâmplă.
>> Aici avem acest tip de valoare mistică.
Avem această 0x0.
Amintiți-vă de la începutul termenului atunci când am vorbit despre numere hexazecimale?
Sau această întrebare puțin la sfârșitul PSET 0 despre cum să reprezinte 50 în hexazecimal?
Modul în care ne scrie numere hex din CS, nu doar pentru a ne confunda
cu numere zecimale, este că noi întotdeauna le prefixul 0x cu.
Deci, acest prefix 0x întotdeauna doar înseamnă interpreteze următorul număr ca număr hexazecimal,
nu ca un șir de caractere, nu ca un număr zecimal, nu ca un număr binar.
Deoarece numărul 5-0 este un număr valid în hexazecimal.
Și este un număr în zecimal, 50.
Deci, aceasta este doar modul în care ambiguitatea.
Deci, 0x0 mijloace hexazecimal 0, care este, de asemenea, zecimal 0, binare 0.
E doar valoarea 0.
Se pare că acest lucru este ceea ce este nul, de fapt, în memorie.
Null este doar 0.
Aici, elementul stocate la argv [1] este nul.
Deci, noi încercăm să compare noastră "CS50 pietre" string într-un șir nul.
Dereferencing Deci null, încercarea de a accesa lucruri de la zero,
cei care sunt, de obicei va provoca un fel de eroare de segmentare sau de alte lucruri rele să se întâmple.
Și se dovedește că nu strcmp verificați pentru a vedea
indiferent dacă sunt sau nu ați trecut intr-o valoare care este nulă.
Mai degrabă, doar merge mai departe, incearca sa-si faca treaba,
și în cazul în care SEG defecte, aceasta SEG defecte, si e problema ta. Trebuie să te duci repara.
Foarte repede, cum am putea rezolva această problemă? Charlotte?
[Charlotte] Puteți verifica dacă ajutorul.
Deci, dacă argv [1] este nul, == 0, atunci intoarce 1, sau ceva de genul [neinteligibil].
Da >>. Așa că e un mod grozav de a face acest lucru, după cum putem verifica pentru a vedea,
valoarea suntem pe cale de a trece în strcmp, argv [1], este nul?
Dacă e nul, atunci putem spune regulă, anulează.
>> O modalitate mai comună de a face acest lucru este de a utiliza valoarea argc.
Puteți vedea chiar aici, la începutul anului principal,
am omis faptul că primul test pe care le facem de obicei, atunci când vom folosi argumente din linia de comandă,
care este de a testa dacă este sau nu o valoare nostru argc este ceea ce ne așteptăm.
În acest caz, ne asteptam cel puțin două argumente,
numele programului plus celălalt.
Pentru ca suntem pe cale de a utiliza al doilea argument chiar aici.
Având în așa un fel de test în prealabil, înainte de apelul nostru strcmp
că testele sau nu argv este de cel puțin 2, ar face, de asemenea, același tip de lucru.
Putem vedea în cazul în care acționează prin rularea programului din nou.
Puteți reporni oricând programul în cadrul GDB, ceea ce este foarte frumos.
Puteți rula, și atunci când treci în argumente la programul dvs.,
le treci în când sunați fugi, nu atunci când cizme sus GDB.
În acest fel puteți să vă păstrați invocând programul dvs. cu argumente diferite de fiecare dată.
Deci alerga, sau din nou, pot Type R, și să vedem ce se întâmplă dacă am scrie "hello".
Se va cere întotdeauna dacă doriți să-l porniți din nou de la început.
De obicei, tu vrei să-l înceapă de la început din nou.
Și la acest punct, se repornește din nou, se imprimă
programul care nu mai avem, buggy1, cu argumentul salut,
și se imprimă asta de iarnă, se spune, "Ai un D," fata trista.
Dar noi nu am SEG vina. Acesta a spus că procesul de ieșit în mod normal.
Deci, care arata destul de bine.
Nu mai vina segment, am facut-o din trecut,
astfel încât se pare că a fost într-adevăr bug vina segmentul pe care am fost obtinerea.
Din păcate, ne spune că vom obține un D.
>> Putem merge înapoi și uita-te la codul și să vedem ce se întâmplă pe acolo
să dau seama ce a fost - de ce ne-a spus că avem un D.
Să vedem, aici a fost acest printf spune că ai un D.
Dacă ne tip listă, după cum vă păstrați lista tastați, se păstrează în jos, prin iterarea programul tău,
asa ca voi arata primele linii ale programului.
Apoi, vom arăta următoarele câteva rânduri, și bucată următoare și următoare bucată.
Și o să încercăm în continuare să meargă în jos.
Și acum vom ajunge la "linia numărul 16 se află în afara razei de acțiune."
Pentru că are doar 15 de linii.
Dacă ajungi la acest punct și întrebându-te, "Ce trebuie să fac?" aveți posibilitatea să utilizați comanda de ajutor.
Utilizați ajutor și apoi să-l numele unei comenzi.
Și veți vedea GDB ne dă tot acest fel de lucruri.
Se spune, "Cu nici un argument, enumeră zece linii mai mult după sau în jurul lista anterioară.
Listă - afișează cele zece linii înainte - "
Deci, haideți să încercați să utilizați lista de minus.
Și care enumeră cele 10 linii precedent; poți să te joci în jurul valorii de cu lista un pic.
Puteți face o listă, lista -, vă pot da chiar un număr de lista, cum ar fi lista de 8,
și-l vom enumera cele 10 de linii în jurul valorii de linia 8.
Și puteți vedea ce se întâmplă aici este că ai o simplă dacă altcineva.
Dacă tastați în CS50 roci, se imprimă "Veți obține un A."
În caz contrar, se imprimă "Veți obține un D."
Păcat oraș. Bine. Da?
>> [Daniel] Așa că atunci când am încercat faci CS50 pietre fără ghilimele,
se spune "Veți obține un D."
Am avea nevoie de citate pentru a face să funcționeze, de ce este asta?
Da >>. Se pare că, atunci când - acesta este un alt tidbit pic de distracție -
cand rulezi programul, în cazul în care l-am rula și am tastați CS50 roci,
la fel ca Daniel a fost spunând că a făcut, și te-a lovit Enter,
încă spune că obține un D.
Și întrebarea este, de ce este asta?
Și se dovedește că ambele noastre terminal și GDB analizare a acestor două argumente ca separate.
Pentru că atunci când există un spațiu, care este implicat în calitate de
primul argument sa încheiat, următorul argument este pe cale să înceapă.
Modalitate de a combina cele în două, sau rău, într-un argument,
este de a utiliza citate.
Deci, acum, dacă l-am pus în ghilimele și rulați-l din nou, vom obține o A.
Deci, doar pentru a recapitula, fără citate, CS50 și roci sunt analizate ca două argumente distincte.
Cu citate, este analizat ca un argument cu totul.
>> Putem vedea acest lucru cu un punct de întrerupere.
Până acum am fost difuzate programul nostru, și a fost difuzate
până când fie se SEG defecte sau afisari o eroare
sau până când aceasta a ieșit și tot a fost total bine.
Acest lucru nu este neapărat cel mai util, deoarece, uneori,
aveți o eroare în programul tău, dar nu cauzează o eroare de segmentare.
Ea nu cauzează programul tău pentru a opri sau ceva de genul asta.
Mod de a ajunge GDB pentru a întrerupe programul tau la un anumit punct
este de a stabili un punct de întrerupere.
Puteți face acest lucru prin stabilirea fie un punct de întrerupere pe un nume de funcție
sau puteți seta un punct de întrerupere pe o anumită linie de cod.
Îmi place pentru a seta puncte de întrerupere pe numele de funcții, pentru că - usor de retinut,
și dacă te duci de fapt, și să vă schimbați codul sursă un pic,
atunci punct de oprire va rămâne, de fapt, la același loc în cadrul codului.
Întrucât dacă utilizați numere de linie, precum și numerele de linie se schimba
pentru că ce adăugați sau ștergeți un cod, apoi puncte de întrerupere, toți vă sunt complet greșit.
Unul dintre lucrurile cele mai comune pe care le fac este setat un punct de întrerupere pe funcția principală.
De multe ori am să boot GDB, voi principal de tip B, apăsați Enter, și că vom stabili un punct de întrerupere
privind funcția principală care spune doar, "Pauza programului de îndată ce începe să ruleze,"
și în acest fel, atunci când am rula programul meu cu, să zicem, CS50 roci ca două argumente
și apăsați Enter, se ajunge la funcția de principal și se oprește chiar în linie foarte în primul rând,
chiar înainte de a evaluează funcția strcmp.
>> Din moment ce am oprit, acum pot începe mucking în jurul valorii de și de a vedea ce se întâmplă
cu toate variabilele diferite care sunt trecute în programul meu.
Aici pot imprima argc și să vedem ce se întâmplă.
Vezi ca argc este 3, deoarece are 3 valori diferite în ea.
Are numele programului, acesta are primul argument și al doilea argument.
Ne poate imprima cele de se uită la argv [0], argv [1], și argv [2].
Deci, acum puteți vedea, de asemenea, de ce acest apel strcmp va eșua,
pentru că vedea că acesta a împărțit CS50 și stâncile în două argumente distincte.
În acest moment, după ce ați lovit un punct de întrerupere, puteți continua să-și intensifice prin intermediul programului tău
linie cu linie, spre deosebire de a începe programul din nou.
Deci, dacă nu doriți să începeți din nou programul și doar continua de aici,
aveți posibilitatea să utilizați comanda continua și continua programul va rula la sfârșitul anului.
Așa cum a făcut-o aici.
Cu toate acestea, în cazul în care am reporniți programul, CS50 pietre, l hit-uri breakpoint-mi din nou,
și de data asta, dacă nu vreau să merg pur și simplu tot drumul prin restul programului,
Eu pot folosi următoarea comandă, pe care am abrevierea de asemenea, cu nr.
Iar acest lucru se va intensifica prin linie de program de linie.
Astfel încât să puteți viziona ca lucrurile executa, ca schimbarea variabile, cum lucrurile se actualizează.
Care este destul de frumos.
Un alt lucru interesant este, mai degrabă decât repetând aceeași comandă de peste si peste si peste, din nou,
dacă te-a lovit doar Enter - deci aici te vezi nu am scris nimic în -
daca am lovit Enter, se va repeta comanda anterioara,
sau comanda GDB precedent pe care mi-am pus doar inch
Eu pot să apăsarea Enter și se va ține pas cu pas prin linie cu linie codul meu.
Mi-ar încuraja să meargă voi verifica celelalte programe buggy, de asemenea.
Nu avem timp pentru a obține prin toate acestea astăzi, în secțiunea.
Codul sursa este acolo, astfel încât să puteți fel de a vedea ce se întâmplă
în spatele scenei, dacă te chiar blocat,
dar cel puțin, practică doar cizme sus GDB,
rularea programului până când se rupe de tine,
obtinerea backtrace, imaginind ceea ce functioneaza accident a fost în,
ceea ce a fost pe linie, imprimarea unor valori variabile,
Doar așa vei obține o simt pentru ea, pentru că va ajuta cu adevarat te duci mai departe.
În acest moment, vom iesi din PIB, pe care veți face cu ajutorul demisia sau doar q.
Dacă programul dvs. este în mijlocul de a rula încă, și nu a ieșit,
se va întreba mereu, "Ești sigur că vrei cu adevărat să renunțe?"
Puteți lovi doar da.
>> Acum ne vom uita la urmatoarea problema avem, care este programul de pisica.
Dacă te uiți pe scurt reorientare și conducte, veți vedea că Tommy foloseste acest program
care imprimă practic totalitatea producției unui fișier de pe ecran.
Deci, dacă am alerga pisica, aceasta este de fapt un program de built-in pentru a aparat,
și, dacă aveți Mac-uri puteți face acest lucru pe Mac ta, daca deschizi terminal.
Și noi - pisica, să spunem, cp.c, și apăsați Enter.
Ce-a făcut această, dacă vom derula un pic și a vedea în cazul în care am fugit linie,
sau în cazul în care am fugit comanda pisica, este literalmente doar imprimate conținutul cp.c la ecranul nostru.
Ne putem rula din nou și vă pot pune în mai multe fișiere împreună.
Astfel încât să puteți face cp.c pisica, iar apoi ne poate înlănțui, de asemenea, fișierul cat.c,
care este programul suntem pe cale de a scrie,
și-l va imprima ambele fișiere back to back la ecranul nostru.
Deci, dacă am derula în sus un pic, vom vedea că atunci când ne-am întâlnit această cp.c pisica, cat.c,
prima tipărit fișierul cp, si apoi mai jos, ea imprimate fișierul cat.c dreapta jos aici.
Vom folosi aceasta pentru a obține doar picioarele noastre ude.
Joaca-te cu imprimare simplă la terminalul, a se vedea modul în care funcționează.
Dacă voi deschide cu gedit cat.c, apăsați Enter,
puteți vedea programul pe care suntem pe cale de a scrie.
Am inclus această placă cazan frumos, așa că nu trebuie să-și petreacă timpul tastarea tot asta.
Noi verificam, de asemenea, numărul de argumente trecut inch
Noi imprimam un mesaj de folosire frumos.
>> Acesta este genul de lucru care, din nou, ca și cum am vorbit despre,
E aproape ca și cum memoria musculare.
Doar amintiți-vă să continui să faci același tip de lucruri
și întotdeauna imprimarea un fel de mesaj de ajutor
astfel încât oamenii să știe cum să rulați programul tău.
Cu pisica, e destul de simplu; suntem doar de gând să treacă prin toate argumentele diferitelor
care au fost trecut la programul nostru, și vom imprima
conținutul acestora atenția la un ecran la un moment dat.
În scopul de a imprima fișiere pentru a ecran, am de gând să faci ceva foarte asemănător
pentru ceea ce am făcut la sfârșitul testului.
La sfârșitul testului, care închiria programul, am avut de a deschide un fișier,
și apoi am avut pentru a imprima la ea.
În acest caz, vom deschide un fișier, și vom citi din ea în loc.
Apoi ne-am de gând să imprima, în loc de un fișier, vom tipări la ecran.
Deci, tipărirea la ecranul ați făcut înainte de toate cu printf.
Așa că nu e prea nebun.
Dar citirea unui fișier este un fel de ciudat.
Vom trece prin asta un pic la un moment dat.
Dacă voi reveni la această problemă în ultima testul dvs., problema 33,
prima linie pe care am de gând să fac aici, deschiderea fișierului, este foarte similar cu ceea ce am făcut acolo.
Deci Stella, ceea ce face ca aspectul linie de genul, atunci când deschideți un fișier?
[Stella] Capital * FILE, Fișier - >> Bine. >> - Este egal cu fopen. Da >>.
Care în acest caz este? E în comentariu.
>> E în comentariu? argv [i] și r?
Exact >>. Dreapta pe. Deci, Stella e dreptate.
Aceasta este ceea ce pare a fi linia.
Vom obține o variabilă flux de fișier, depozitați-l într-un * FILE, astfel încât toate capacele,
FILE, *, și numele acestei variabile va fi fișier.
Am putea-o numi tot ceea ce ne place. Am putea numi first_file, sau file_i, orice ne-ar plăcea.
Și apoi numele fișierului a fost adoptată în pe linia de comandă pentru acest program.
Deci, este stocat în argv [i,] și apoi vom deschide acest fișier în modul citire.
Acum, că ne-am deschis dosarul, ceea ce este lucrul pe care noi întotdeauna trebuie să vă amintiți să facă
ori de câte ori am deschis un fișier? Închide-o.
Deci Missy, cum putem inchide un fisier?
[Missy] fclose (file) >> fclose (file). Exact.
Mare. Bine. Dacă ne uităm la acest comentariu de făcut aici,
se spune, "Deschide argv [i] și a imprima conținutul sale la stdout."
>> Out Standard este un nume ciudat. Stdout este doar modul nostru de a spune
vrem să-l imprimați să terminalului; vrem să-l imprimați fluxul de ieșire standard.
Putem obține de fapt scapa de acest comentariu aici.
Am de gând să-l copiați și lipiți-l din moment ce e ceea ce am făcut.
În acest moment, acum avem de a citi fișierul de biți bit.
Am discutat despre o serie de moduri de fișiere de lectură.
Care sunt cele favorite pana acum?
Care modalități ați văzut sau nu vă amintiți, pentru a citi fișiere?
[Daniel] fread? Fread >>? Deci, fread este unul. Jimmy, știi și alții?
[Jimmy] Nr >> Bine. Nope. Charlotte? Alexander? Orice alții? Bine.
Deci, celelalte sunt fgetc, este una care vom folosi o mulțime.
Există, de asemenea, fscanf; voi vedea un model aici?
Toate încep cu f. Nimic de a face cu un fișier.
Nu e fread, fgetc, fscanf. Acestea sunt toate funcțiile de citire.
Pentru scrierea avem fwrite, avem fputc loc de fgetc.
De asemenea, am dori fprintf am văzut-o pe test.
Deoarece aceasta este o problemă care implică citirea dintr-un fișier,
vom folosi una din aceste trei funcții.
Noi nu vom utiliza aceste funcții jos aici.
Aceste funcții sunt toate găsite în I / O standard bibliotecă.
Deci, daca te uiti la partea de sus a acestui program,
puteți vedea că am inclus deja fișierul antet pentru I / O standard bibliotecă.
Dacă vrem să aflăm care dintre noi vrem să folosim,
putem deschide întotdeauna paginile man.
Deci, putem scrie stdio om
si citeste tot despre stdio de intrare și de ieșire în funcțiile C.
Și putem vedea deja oh, uite. E menționând fgetc, se menționează fputc.
Astfel, puteți detalia un pic si uita-te la, să zicem, fgetc
si uita-te la pagina de manual a lui.
Puteți vedea că merge împreună cu o grămadă de alte funcții:
fgetc, fgets, getc, getchar, devine, ungetc, și darea ei de caractere si siruri de caractere.
Deci, acesta este modul în care citim în caractere și șiruri de fișiere de pe intrarea standard,
care este în esență de la utilizator.
Și acest lucru este cum o facem în actuala C.
Deci, acest lucru nu se utilizează getString și funcțiile getchar
pe care am folosit din biblioteca CS50.
Vom face această problemă în câteva moduri
astfel încât să puteți vedea două moduri diferite de a face asta.
Atât funcția fread că Daniel mentionat si fgetc sunt bune moduri de a face acest lucru.
Cred că fgetc este un pic mai usor, deoarece are doar, după cum vedeți,
un singur argument, * FILE pe care noi încercăm să citească personaj din,
și valoarea sa returnata este un int.
Și aceasta este un pic confuz, nu?
>> Pentru ca ne apropiem un caracter, așa că de ce nu acest retur un char?
Voi aveți orice idei cu privire la ce acest lucru nu s-ar putea întoarce un char?
[Răspunde Missy, neinteligibil] >> Da. Deci Missy e dreptate.
Dacă e ASCII, atunci acest lucru ar putea fi întreg mapată la un char reală.
Ar putea fi un caracter ASCII, și asta e bine.
Asta e exact ceea ce se întâmplă.
Suntem folosind un int pur și simplu pentru că are mai mulți biți.
E mai mare decât un char; char noastră are doar 8 biți, care pe 1 octet noastre 32-bit mașini.
Și un int are valoare toate cele 4 octeți de spațiu ".
Și se dovedește că modul fgetc funcționează,
dacă vom defila în jos, în rezumatul nostru în această pagină om un pic,
defila tot drumul în jos. Se pare că ei folosesc această valoare special numit EOF.
E o constantă specială în valoare de retur a funcției fgetc
ori de câte ori te-a lovit sfârșitul fișierului sau în cazul în care veți primi o eroare.
Și se dovedește că a face aceste comparații cu EOF în mod corespunzător,
doriți să aveți această sumă suplimentară de informații pe care le au într-o int
spre deosebire de folosind o variabilă char.
Chiar dacă fgetc este obtinerea efectiv un caracter dintr-un fișier,
doriți să vă amintiți că se întoarce ceva care este de tip int pentru tine.
Acestea fiind spuse, e destul de usor de utilizat.
O să ne dea un caracter, așa că tot ce trebuie să faceți este tot întreb dosar,
"Dă-mi următorul caracter, dă-mi următorul caracter, dă-mi caracterul următor,"
până când vom ajunge la sfârșitul fișierului.
Și că va trage într-un caracter la un moment dat din fișierul nostru,
și apoi putem face ce ne place cu ea.
Noi putem stoca, putem adăuga la un șir, putem imprima.
Nimic din toate astea.
>> Zoom înapoi și merge înapoi la programul nostru cat.c,
dacă am de gând să utilizeze fgetc,
cum am putea aborda această următoarea linie de cod?
Vom folosi - fread va face ceva ușor diferit.
Și de data asta, suntem doar de gând să utilizeze fgetc pentru a obține un caracter la un moment dat.
Pentru a procesa un fișier întreg, ceea ce s-ar putea trebuie să facem?
Câte personaje sunt acolo într-un fișier?
Există o mulțime. Deci, probabil, veți dori pentru a obține unul
și de a lua apoi altul și altul și să obțineți un alt.
Ce fel de algoritm crezi că am putea avea de a utiliza aici?
Ce tip de -? [Alexander] A pentru buclă? Exact >>.
Un anumit tip de bucla.
A pentru buclă este de fapt o mare, în acest caz.
Și ca și cum ai spune, se pare ca va doriti o bucla peste întregul dosar,
obținerea unui personaj la un moment dat.
Orice sugestii cu privire la ceea ce s-ar putea ca arata ca?
[Alexander, neinteligibil]
Bine >>, spune-mi în limba engleză ceea ce încerci să faci? [Alexander, neinteligibil]
Deci, în acest caz, se pare că suntem doar încercarea de a bucla peste întregul dosar.
[Alexander] Deci, i > -?
Cred ca marimea fisierului, nu? Dimensiunea - Vom scrie doar ca asta.
Dimensiunea de fișier pentru moment, i + +.
Deci, se dovedește că modul în care face acest lucru utilizând fgetc, iar acest lucru este nou,
este că nu există nici o modalitate ușoară de a obține doar dimensiunea unui fișier
cu acest "sizeof" tip de construcție pe care le-ați văzut până acum.
Când ne-am folosi această funcție fgetc, vom introduce un fel de
noua sintaxă, funky, pentru a prezenta pentru bucla, în cazul în care în loc de a folosi doar un contor de bază
pentru a merge caracter cu caracter, vom trage un caracter la un moment dat,
un caracter la un moment dat, și modul în care știm că suntem la sfârșitul
nu este atunci când ne-am numarat un anumit număr de caractere,
dar atunci când personajul ne scoate acest scop este deosebit de caracter fișier.
Astfel încât să putem face acest lucru prin - Eu numesc asta ch, și noi o să-l inițializa
cu apel prima noastră pentru a obține primul caracter din fisier.
Deci, această parte chiar aici, acest lucru este mergi la a lua un caracter din fisier
și-l păstrează în variabila ch.
Vom continua să facem acest lucru pana cand vom ajunge la sfârșitul fișierului,
pe care le face prin testarea pentru personajul nu este egal cu acel caracter EOF specială.
Și atunci în loc de a face CH + +, ceea ce ar incrementa valoarea doar,
așa că, dacă citim un un fișier de, un capital A, să zicem,
CH + + ne-ar da b, iar apoi am obține c și d, apoi.
Asta nu e clar ce ne dorim. Ceea ce ne dorim aici
în acest bit este ultima vrem să obțineți următorul caracter din fișierul.
>> Deci, cum am putea obține următorul caracter din fișierul?
Cum ajungem primul caracter din fișierul?
[Student] fgetfile? >> Fgetc, sau, îmi pare rău, ai avut dreptate.
Am greșit chiar acolo. Deci da.
Aici în loc de a face CH + +,
suntem doar de gând să sun fgetc (fișier) din nou
și stoca rezultatul în variabila ch noastră aceeași.
[Întrebare Student, neinteligibil]
Acest lucru este în cazul în care >> tipii ăștia FILE * sunt speciale.
Modul în care acestea funcționează este că - atunci când deschideți prima - atunci când faci mai întâi că apelul fopen,
* FILE eficient servește ca un pointer la începutul fișierului.
Și apoi de fiecare dată când suna fgetc, se misca un caracter prin fișierul.
Deci, ori de câte ori te sun asta, te incrementare indicatorul fișierului de un caracter.
Și când te fgetc din nou, te muți în alt personaj
și un alt personaj și un alt personaj și un alt personaj.
[Întrebare Student, neinteligibil] >> Și that - Da.
E un fel de magie acestei sub capota.
Tu doar ține de incrementare prin intermediul.
În acest moment, sunteți în stare să lucreze efectiv cu un caracter.
Deci, cum am putea imprima acest pentru a ecran, acum?
Putem folosi același lucru pe care am folosit printf înainte.
Pe care le-am folosit tot semestrul.
Putem numi printf,
și putem trece la caracterul la fel ca asta.
Un alt mod de a face acest lucru este, mai degrabă decât folosind printf și având de a face acest șir format,
putem folosi, de asemenea, una dintre celelalte funcții.
Putem folosi fputc, care imprimă un caracter ecran,
cu excepția cazului dacă ne uităm la fputc - lasă-mă să micșora un pic.
Vedem ce e frumos este nevoie în personajul pe care am citit cu ajutorul fgetc,
dar atunci trebuie să ne dea un curs de apa pentru a imprima la.
Putem folosi, de asemenea, funcția putchar, care va pune direct în standard.
Deci, există o grămadă de opțiuni diferite pe care le putem folosi pentru imprimare.
Sunt toate în standard I / O bibliotecă.
Ori de câte ori doriți să imprimați - așa printf, implicit, va imprima la standardul specială în curs de apa,
care este faptul că stdout.
Deci, putem referi doar la ea ca un fel de magie această valoare, consolă aici.
Hopa. Pune punct și virgulă exterior.
>> Aceasta este o mulțime de informații noi, Funky aici.
O mulțime de acest lucru este foarte idiomatică, în sensul că aceasta este codul
care este scris acest fel doar pentru că e curat pentru a citi, ușor de citit.
Există multe moduri diferite de a face acest lucru, multe funcții diferite pe care le puteți utiliza,
dar avem tendința să urmeze doar aceste modele același de peste si peste.
Asa ca nu fi surprins dacă vedeți cod ca asta vine din nou și din nou.
Bine. În acest moment, avem nevoie de a sparge pentru a doua zi.
Mulțumesc că ai venit. Vă mulțumim pentru vizionarea daca esti on-line. Și ne vedem săptămâna viitoare.
[CS50.TV]