[? DAN ARMADARAS:?] Bună, Im [? Dan Armadaras?]. Astăzi, vom fi uitat la depanare. Nu numai vom vorbesc despre unele tehnici, dar, de asemenea, ne vom uita la unele dintre caracteristicile conținute în cadrul IDE CS50 care permit te pentru a depana cu ușurință un program. Doar un exemplu de ceva care poate merge prost și este de fapt ceva pe care le-am văzut deja înainte. În acest caz, acesta este un program de C care acceptă un număr întreg de la utilizator, împarte câte două, și furnizează de ieșire înapoi la utilizator. Acum de la ceea ce am văzut mai devreme în prelegeri, știm că acest lucru va provoca de fapt, anumite tipuri de probleme Divizia atunci când avem numere impare. Mai exact, vom arunca doar departe ceva după virgulă. Acum, știm că acest lucru se întâmplă să fie cazul. Și dacă l-am rula, putem confirma suspiciunile noastre, în primul rând, prin elaborarea. Și apoi, de funcționare și introducerea unui număr impar. Acest lucru este nimic nou. Dar aceasta este de fapt o exemplu de un bug care poate exista în cadrul unui program mai larg care devine mai greu pentru a urmări în jos. Chiar dacă știm ce problema este, adevărata esența problemei ar putea fi încercarea de a identifica în special în cazul în care se produce eroarea, identificarea a ceea ce această problemă este, iar apoi fixare. Deci oferi acest lucru ca un exemplu de ceea ce ar putea fi ceva ca stim deja, dar poate fi îngropat în alte elemente ale codului. Deci, deschiderea acestei altă sursă Codul fișier ca un exemplu, această problemă divizie este acum parte a unui program mai larg. Încă ar putea fi un pic bit contrived, iar noi ar putea cu ușurință identifica, mai ales deoarece noi doar discutăm acest lucru. Dar ne putem da seama că această problema poate exista pe o scară mai mare. Dacă am compila acest lucru și acum rulați-l, introduceți un număr impar, putem vedea că nu ne precis ieșire ca să putem fi așteptat. În acest caz particular, am putea spune că ne-am vreau sa numere toate numerele de la o pana la un numar specific. Și putem vedea că ne au o varietate de probleme aici dacă suntem scoate, pur și simplu, 0 și 1 atunci când oferim o intrare de 5. Deci, noi știm deja că există o problemă aici. Dar noi nu să cunoască cu exactitate în cazul în care această problemă, de fapt există. Acum, unul dintre modurile în care putem încerca pentru a rezolva această este ceva ce ne-am fost deja prezentat. Putem doar folosi pe o scară mai mare. Pe linia 14, avem Această funcție printf, care ne permite pentru a imprima statului de diverse piese de informații. Și acest lucru este ceva ce ar trebui să fructifice în cadrul programului dumneavoastră pentru a încerca să dau seama exact ce este întâmplă în diferite linii de cod. Deci, chiar dacă acest lucru nu este rezultatul final că de fapt doresc să producă din acest program, noi încă ar putea avea unele depanare Declarații unde am pot încerca să dau seama exact ceea ce se întâmplă în interiorul codul nostru. Deci, în acest caz, voi printf cu tag-ul de depanare. În acest caz, aceasta este doar un șir de depanare că sunt up-inscrie astfel încât să devină foarte clar în producția de codul meu ceea ce este că vreau să arăt. Și de ieșire de aici numărul care le-am calculat. În acest caz, am putea vreau să știu cu precizie ceea ce se întâmplă înainte și după unele calcule specifice. Deci, s-ar putea folosi un printf înainte și după aceea linie de cod. În acest caz, am putut chiar fac din el un pic mai mult clar prin a spune depanare înainte și depanare după așa care nu mă confunda cu mai multe linii, care arata identic. Acum, dacă am recompilați această și a alerga aceasta, introduceți un număr de cinci ca, din nou, putem vedea că avem acum ieșire înainte și după și pentru a găsi că nu am făcut-o clar divizare sau clară cu numărul că de fapt vrei sa faci. Acum, în acest caz, aceasta este nu într-adevăr o ieșire clar. Nu e chiar un rezultat clar că vrem din acest program special. Și acest lucru este, din nou, un pic contrived. Dar, poate, unul dintre lucrurile pe care am putea face în cazul în care caietul de sarcini a declarat că vrem să împartă acest lucru prin 2 și se adaugă 1-- așa în alte cuvinte, vrem să rotunjească up-- apoi am să știe că am putea face acest lucru special, în acest caz. Acum aici știm că vom fi posibilitatea de a adăuga 1 la numărul nostru înjumătățit. Să recompilați acest și confirmă faptul că această se comportă modul în care dorim să. Putem vedea că acum înainte având, avem numărul 5. După ce, avem numărul 3, care, conform specificatiilor noastre, este ceea ce am vrut să fac. Dar dacă ne uităm la ieșire aici, putem vedea că am putea avea un alt bug totul, ceea ce este că începem Nr nostru de la 0. Acum, din nou, acest lucru este ceva care le-am văzut în trecut și putem repara destul de ușor. Dar, în acest caz, ne-am avut, de asemenea, în beneficiul de utilizare a declarației printf direct în interiorul pentru bucla să știe exact unde care eroare a fost loc. Declarații Deci printf sunt foarte util în a ajuta te determina unde, tocmai în codul sursă, o eroare specific are loc. Și este, de asemenea, important să realizăm că, așa cum ne scrierea de cod, am putea avea ipoteze cu privire la starea unui program. Sau am putea avea ipoteze despre ce parte a programului este, de fapt corecte sau incorecte, atunci când mai târziu cum am construi pe acest program și să-l dintr-o parte complexă și mai mare program de că ne dăm seama că unele aspecte de care este de fapt buggy. Utilizarea printf poate ajuta cu adevarat restrânge și de a identifica regiunile un program care nu pot se comporta exact modul în care ne se așteaptă, bazate pe ipoteze noastre. Dar există alte instrumente disponibil, de asemenea, care ne permit să încercați să descoperiți unde o eroare se produce și, de asemenea, în mod specific, ce lucruri se întâmplă în interiorul programului. Deci, folosind printf este foarte când ne-o dorim util pentru a identifica zonele specifice de un program care avea unele bug. Dar devine, de asemenea, plictisitor după un timp. În acest caz, aceasta este o Programul relativ simplu cu doar una sau două variabile. Si devine foarte ușor pentru noi să imprima valoarea acestor variabile în contextul programului mai larg. Dar am putea avea un alt program care are multe variabile. Și nu poate fi destul de atât de ușor de utilizat printf pentru a încerca să evalueze ceea ce se întâmplă la fiecare dintre aceste variabile ca programul este de executare. Există un program care există numit un program de depanare. În acest caz, cel care vom utilizare este debugger GNU, sau GDB, care ne permite să inspecteze interne lucrări de un program într-un mult mai mod detaliat. Putem executa de fapt GDB din linia de comandă aici prin simpla tastarea GDB și comandă care ne-o dorim pentru a depana. În acest caz, conta. Acum, în acest caz, putem vedea că ne aduce la un prompt care spune GDB. Și putem, de fapt executa comenzi pentru GDB pentru a începe de fapt executarea Programul, oprește-te în anumite puncte, evalua variabilele și inspecta variabilele care există în starea de programul la acel moment, și așa mai departe și așa mai departe. Acesta oferă o mulțime de puterea de a ne. Dar doar așa se întâmplă că IDE CS50, de asemenea, oferă o interfață grafică sau un utilizator interfață pentru GDB care ne permite să facem acest lucru fără a fi nevoie linie de comandă fel interfața sau la toate, chiar. Modul în care pot accesa că este folosind butonul depanare la foarte de sus a IDE CS50. Acum, în trecut, ceea ce avem văzut este că vom folosi comanda linie pentru a compila și apoi executați un program de. Butonul de depanare nu aceste două etape. Dar, de asemenea, va aduce la Fila debugger pe extrema dreaptă care ne permite să inspecteze o varietate de proprietăți ale programului așa cum este de executare. Dacă am faceți clic pe depanare, în acest caz, se va aduce o filă nouă în consola fereastră în partea de jos. Și puteți vedea că această filă are unele informații la foarte de sus. Și putem ignora în mare măsură acest lucru. Dar unul dintre lucrurile pe care le care ne-o dorim pentru a observa este faptul că ieșirile același lucru pe care îl ar obține dacă am încercat să ruleze face pe programul C în fereastra terminalului. Aici, putem vedea că se execută zăngănit, și are o varietate de steaguri, și este compilarea dosarul nostru count.c, care a fost fila selectată la momentul că am lovit de depanare. Deci acest lucru este foarte util, deoarece acum folosind acest buton depanare, putem compila simultan și apoi executa programul pe care suntem de fapt doriți să o executați. Unul dintre steagurile care este importantă, în acest caz, am fost, de fapt, folosind pentru cel mai lung timp dar, de asemenea a făcut doar câteva mână fluturând [auzite], care este cea de aici. În zăngăni, se spune -ggdb3. În acest caz, ceea ce suntem spune zăngăni, compilator nostru, este că vrem să compila programul nostru. Dar oferă, de asemenea, care sunt numit informații simbol astfel încât compilatorul are de fapt acces la o mulțime de informații care stau la baza conținute în cadrul programului. Mai precis, numărul de funcții pe care le am, numele acestor funcții, variabilele, tipurile că aceste variabile sunt, și o varietate de alte lucruri care ajuta debugger efectuarea operației acestuia. Acum mai e ceva care este important de menționat când suntem discutăm de funcționare un program în acest fel. Observați că are de fapt adus o nouă filă în consolă nostru a lungul părții inferioare. Noi nu mai trebuie să interacționeze direct cu fereastra terminal. Dar această nouă filă este de fapt, o fereastră de terminal. Pur și simplu este specific de funcționare Programul care le-am creat. Observați că în partea de jos, în combinație cu unele de ieșire de clang compilator și GDB, care putem ignora în mare măsură, se arată de fapt datele de ieșire ale programul nostru de la foarte partea de jos. Acum este important să realizăm că aceasta fereastra de fapt vă va arăta ieșire din program dar, de asemenea, poate accepta intrare pentru acest program, de asemenea. Deci observați că spune Vă rugăm să introduceți un număr, care este aceeași ieșire pe care am avut a avut în fereastra terminalului înainte. Dar este acum arătat în această nouă filă. Pot introduce un număr. Și va de fapt funcționează ca ne asteptam arătându-ne depanare noastră, de ieșire, de ieșire care ar putea fi buggy, cum am văzut mai înainte. Și chiar la partea de jos, ea are de fapt, unele de ieșire suplimentare din PIB, doar spune că acest program a finalizat. Acum, ați văzut în acest special alerga prin, aceasta nu a fost deosebit utile, deoarece chiar deși am avut venit din meniul debugger up, aceasta era încă un program care rulează. La nici un punct a făcut de fapt pauză de executie pentru noi pentru a putea inspecta toate variabilele conținuți. Mai e ceva că trebuie să facem pentru pentru a obține GDB să recunoască faptul că ne-o dorim pentru a întrerupe executarea programului și să nu permită doar să procedeze în mod normal, așa cum ne-ar în orice alt caz. În scopul de a întrerupe executarea, la o linie specifică, avem nevoie pentru a crea ceea ce este numit un punct de pauză. Și un punct de pauză este foarte usor creat în acest CS50 IDE prin luarea mouse-ul și făcând clic direct la stânga de un numar linie specifică. După ce am făcut asta, un punct roșu Apare, ceea ce indică că această linie este acum un punct de pauză. Și data viitoare pe care am rulat GDB l, va opri executia la acel punct de spargere atunci când aceasta ajunge ca linie de cod. Acum, acest lucru este un important lucru pentru a realiza că nu este neapărat cazul în care fiecare linie de cod este, de fapt accesibilă. Daca as fi fost de a crea o funcție aici, pentru f-- void example-- și de a face doar o linie de imprimare here-- salut world-- dacă nu eu numesc această funcție, acesta va fi cazul în care, dacă am stabilit un punct de pauză aici, funcția nu va fi numit. De aceea, această special punctul pauză nu va întrerupe de fapt executarea programului. Deci, haideți să spun că am crea corect un punct de pauză pe unele linie de cod care va fi real executate. Acum, în acest caz, aceasta este prima linie în funcția principală. Deci, va fi cu siguranță cazul că, de îndată ce voi începe executarea, prima linie va fi atins. GDB va întrerupe executarea. Și apoi, voi fi capabil să interacționa cu debugger. Puteți seta mai multe linii ar fi valori critice, dacă doriți. Putem crea, de asemenea, o linie de până aici, în acest segment de cod care nu va fi atins. Și putem, de asemenea, seta o mai jos. Motivul pentru care ne-ar vrei sa faci acest lucru ne vom du-te în un pic mai mult detaliu intr-o clipa. Deci, pentru moment, lasă-mă să dezactivați aceste puncte de pauză suplimentare astfel încât să ne putem uita la ceea ce se întâmplă atunci când am o pauză singur punct în programul meu. Am făcut unele modificări la acest program. Așa că am nevoie să-l salveze. Voi faceți clic pe de depanare, astfel încât pot începe elaborarea și apoi executarea debugger. Vom vedea că, după momente, linie care am selectat ca pauză punct este evidențiat în galben. Se poate observa, de asemenea, că, în dreapta sus în panoul de depanare că icoana pauză sa transformat într-o pictogramă joc pic. Acest lucru înseamnă că avem pauză execuție, în acest caz particular. Și lovind pe butonul Redare va ne permit să-și reia executarea în acel moment specific. Observați că există o serie de alte butoane disponibile în acest panou de depanare, deasemenea. Pasul pe care îmi permite să executa că o linie de cod și pas pe la acea linie la o viitoare, care, în acest caz, ar însemna că printf declarație este executată. Și se va face o pauză, apoi execuție pe linia 13, cum ar fi așa. Și există, de asemenea, un pas în funcție, care este util dacă am creat alte funcții în altă parte în codul sursă. Și vreau să-și intensifice în aceste funcții, mai degrabă decât executa care funcționează ca un întreg. Dar ne vom uita mai mult la etapa în funcție într-o clipă. Acum, observați alte lucruri care Există de fapt, în acest panou de depanare. Avem acest panou numită Call Stack, care ne arată unde suntem. În acest caz, noi suntem în interiorul din funcția principală. Script-ul nostru se numește count.c. Și se întâmplă să fie pe linia 13, coloana unu, care este exact ceea ce regiunea a subliniat din codul sursă indică, de asemenea. Acum, observați că acest lucru arată, de asemenea, în secțiunea variabilă locale toate variabilele care există în această funcție. Este important să rețineți că toate variabilele va apărea în această variabilă locală secțiune în cadrul unei funcții, chiar înainte de a fi definite. Putem vedea aici că avem o variabilă numit num, are o valoare implicită de la 0, și este de tipul int. Acum, înainte de a inițializa de fapt toate aceste variabile, nu suntem neapărat garantat pentru a vedea o valoare de la 0. Și în funcție de alte executii care le-au efectuat și starea de memorie, atunci când executați de fapt acest program, s-ar putea găsi pe care le nu văd valori de 0 și, în schimb, alte numere de nebun. Dar nu vă faceți griji despre asta. Nu va fi relevant până inițializați de fapt valoarea. Acum, în acest caz, putem vedea că Am efectuat unele rezultate. Și eu, chiar acum, o pauză de executie. Dar, în acest caz, ceea ce Eu chiar vreau să fac este să-și intensifice acum peste această linie de cod astfel încât să pot de fapt interogarea utilizatorului pentru care int care vrem sa folosim în programul nostru. Acum, în acest caz, atunci când Am lovit pas peste, aviz că pauză sau, mai degrabă CV-ul Butonul a schimbat la acest buton Pauză deoarece acest cod este, de fapt de executare. Ce se întâmplă acum este faptul că este ne așteaptă pentru a introduce câteva informații așa cum putem vedea prin textul nostru de ieșire în partea de jos. Deci acum, aceasta este de fapt, nu se opri, chiar dacă, un fel de pare, să fie pentru că nu se întâmplă nimic. Dar doar așa se întâmplă că, în cazul meu specific pe linia 13, Sunt de așteptare pentru introduse de utilizator. Și așa GDB nu este capabil de a inspecta un program ca acesta este în funcțiune. Acum, data viitoare pe care am intra unele input-- așa că vom introduce acest număr de 5, așa cum am văzut în past-- lovit de returnare, iar noi observă că, imediat, pauze GDB și, din nou, subliniaza linia următoare. Dar observați că acum, ca un rezultat al introducerea nostru o valoare, am actualizat acea valoare în interiorul variabilelor noastre locale, care este foarte util să cunoască cu exactitate ce acest număr a fost în memorie. Acum pot permite acest program pentru a continua joc până la sfârșitul execuției sale prin lovirea Reluare. Putem vedea că foarte repede nu termina programul de executare cu aceeași ieșire pe care le a avut înainte, debugger se închide, iar acum acest program sa oprit complet. Am arată că numai pentru scopul de a vedea ceea ce se întâmplă atunci când ne-am lovit de fapt Reluare. Dar noi, de fapt de gând să vreau să mă întorc în acest program astfel încât să putem încerca pentru a depana exact ceea ce se întâmplă. Acum, că eu sunt, folosind debugger, am putea nu au nevoie de aceste declarații depanare printf. Așa că am putea să le eliminați ca voi face acum doar pentru a reveni la codul nostru simplu că am avut-o acum un moment. Acum, când am salva programa și executa, va, din nou, du-te la faptul că inițial punct pe care am avut pe linia 11 rupe. Și voi fi în măsură să inspecteze variabile mele ca vreau sa fac. Este doar așa se întâmplă că această parte nu este foarte interesant, Și știu că am de gând pentru a imprima această declarație. Vă rugăm să introduceți un număr. Și apoi, eu știu că am de gând pentru a cere utilizatorului pentru care întreg. Deci, poate, de fapt, vreau să se mute meu punct de pauză un pic mai jos. Puteți elimina puncte de pauză făcând clic, din nou, în mod direct în partea stângă a liniei care numărul. Care red dot va dispărea, indicând că punct de pauză este acum plecat. Acum, în acest caz, execuție a fost întreruptă. Și așa nu este de fapt de gând să relua în acest caz particular. Dar pot seta o pauză litera un pic mai târziu. Și când am acum CV-ul meu cod, se va relua și spune punctul de care punct de spargere. Din nou, am lovit Reluare. Nu pare a fi ceva se întâmplă. Dar asta e din cauza mea Codul este în așteptare pentru intrare. Voi introduce un număr de 5, apăsați pe Enter, și acum următorul punct de spargere va fi lovit. Acum, în acest caz, aceasta este linia de cod că, mai înainte, am stiut sa întâmplat să fie buggy. Deci, haideți să evalueze ceea ce se întâmplă în acest moment special de timp. Atunci când o linie este evidențiat, acest line nu a fost încă executată. Deci, în acest caz, putem vedea că am un număr, care Am un întreg numit num care are o valoare de 5. Și am de gând să fie performante unele matematica la acel număr. Dacă aș pas peste care, putem observați că valoarea de num sa schimbat în conformitate cu aritmetică că am făcut de fapt. Și acum că suntem de acest lucru pentru bucla interior sau acum că pentru bucla în sine este evidențiată, vom vedea că avem o nouă variabilă-am numit ca va fi utilizat în bucla for. Acum, amintiți-vă, înainte de care am menționat că, uneori, esti O să văd un fel de nebun Numerele în mod implicit, înainte de acel număr sau care este variabila de fapt inițializat. Putem vedea că tocmai aici, în această variabilă numit i, care nu are a fost încă inițializat în momentul evidențierea. Dar putem vedea că are unele număr că nu ne-ar aștepta de fapt. Asta e ok. Nu vă faceți griji pentru că nu am de fapt, inițializat acest număr până când am pas pe această linie și valoarea i a fost inițializat cu valoarea 1. Deci, pentru a vedea că de fapt cazul, să-și intensifice pe. Putem vedea acum că line a fost executată. Și noi suntem acum subliniind această linie printf. Și putem vedea acum cum valorile noastre de i si 3 s-au schimbat în timp. Acest lucru este foarte util pentru a face, de fapt, este să-și intensifice prin linii în mod repetat. Și puteți găsi de fapt, ceea ce se întâmplă în interiorul pentru bucla dvs. și ce se întâmplă cu variabile în interiorul că pentru bucla ca și execuția programului apare un pas la un moment dat. Acum, în acest moment, am păși peste suficient că acum eu sunt la sfârșitul programului meu. Dacă aș pas peste asta, va încetează de fapt de executie așa cum am văzut în trecut. Lasă-mă să reporniți acest, încă o dată, astfel încât că pot indica altceva, deasemenea. În acest caz, este acum mă întrebi, din nou, pentru un număr, care Voi, din nou, introduceți. Dar de data asta, am de gând să intre în un număr mai mare, astfel încât pentru bucla va repeta de mai multe ori. În acest caz, am de gând pentru a introduce o valoare de 11. Acum, din nou pentru că aș stabilit un punct de pauză la linia 15, este de gând să sublinieze faptul că linia. Putem vedea că nostru Numărul 11 ​​este corect reprezentată în variabilele noastre locale. Trecând peste asta, putem acum ceas ce se întâmplă cu valoarea noastra de i așa cum am proceda în interiorul asta pentru bucla. Acesta se crește de fiecare dată când ajunge la partea de sus a că, pentru bucla. Acum, unul dintre lucrurile pe care ar putea fi util de făcut în timpul execuției acestui program este pentru mine de a efectiv schimba midstream variabilele pentru a vedea ce se întâmplă cu programul meu. În acest caz, pot de fapt faceți dublu clic pe valoarea. Observați că acesta devine un câmp de text. Acum pot intra diferite valoare cu totul pentru a vedea cum se comportă programul meu când m-am schimbat variabila. Acum, în acest caz, variabila I conține acum valoarea de 10. Dar programul este încă opri în execuție. Când m-am pas peste, am vedea că Am valoare, pe care am introdus ca 10, nu este mai mare decât valoarea de num, care provoacă imediat pentru bucla pentru a opri executarea. Acum, că nu este singurul motiv pentru care ar doriți să modificați variabila în loc. S-ar putea dori de fapt, pentru a încerca să-l modifice, astfel încât să puteți continua executarea unei bucle sau astfel încât să puteți modifica o valoare înainte de a ajunge unele set specific de aritmetică că sunteți pe cale de a efectua. Deci, acum că am schimba de fapt valoarea lui I ca programul a fost de executare, aceasta a cauzat de bucla pentru a iesi prematur, deoarece, dintr-o dată, m-am întâmplat să fie mai mare decât valoarea de num, ceea ce înseamnă că pentru bucla nu mai sunt necesare pentru a fi executate. Mai mult, sa întâmplat să fie cazul în care am schimbat valoarea lui I când a fost evidențiată linia 17, care a fost punctul în timp că pentru executarea bucla a fost de fapt în curs de evaluare. Dacă aș fi schimbat valoarea Am pe o linie diferită, spun 19, ne-ar fi văzut diferit Comportamentul deoarece linia 19 ar fi au executat înainte de bucla condiție a fost reevaluat. Acum, în acest moment, eu sunt, din nou, la sfârșitul acestui program. Și eu pot permite acest lucru pentru a trece la permite programul meu pentru a iesi in mod natural. Dar există o serie de lucruri care sunt importante pentru a ține departe din această discuție special. Aveți nevoie pentru a evalua propriile ipoteze despre modul în care codul ar trebui să fie comporta. Orice timp credeți că unele bucata de cod știi se întâmplă la locul de muncă, care ar putea fi un steag rosu pentru a merge înapoi și să evalueze, și asigurați-vă că că presupunerea ta de cum codul funcționează este, de fapt adevărat la modul în care este exprimată în codul sursă. Dar chiar mai mult pentru a punct a fost, când suntem folosind debugger, puteți pune puncte de întrerupere la diferite linii de cod, ceea ce va determina debugger la pauză execuție la fiecare dintre aceste linii astfel încât să puteți evalua de memorie sau chiar modifica în loc. Și din nou, amintiți-vă că puteți creați mai multe puncte de întrerupere, astfel încât să poate relua, de asemenea, executarea, săriți peste porțiuni mari de cod, și-l va opri în mod automat la următorul punct de spargere. Există de fapt mai avansat caracteristici ale debugger, precum și. Dar va trebui să vă referiți la câteva videoclipuri ulterioare în scopul de a tachineze cu adevărat afară cum de a utiliza aceste funcții speciale. Pentru moment, vă mulțumesc foarte mult pentru vizionarea. Și de bună depanare noroc.