[? DAN ARMADARAS:?] Hej, Jeg er [? Dan Armadaras?]. I dag vil vi se på fejlfinding. Ikke alene vil vi tale om nogle teknikker, men også vi kommer til at se på nogle af de funktioner, der er indeholdt i CS50 IDE, der tillader du nemt fejlsøge et program. Blot et eksempel på noget, der kan gå galt og det er faktisk noget at vi allerede har set før. I dette tilfælde er det en C program der accepterer et heltal fra brugeren, deler den med to, og giver output tilbage til brugeren. Nu fra hvad vi har set tidligere i foredrag, vi, at dette rent faktisk vil medføre specifikke typer af division problemer når vi har ulige numre. Konkret vil vi bare smide væk noget efter kommaet. Nu ved vi, at dette sker for at være tilfældet. Og hvis vi kører det, kan vi bekræfte, vores mistanke, første, ved at indsamle. Og så, ved at køre og indtastning et ulige antal. Dette er ikke noget nyt. Men det er faktisk en eksempel på en fejl, der kan eksistere inden for et større program der bliver sværere at opspore. Selv om vi ved, hvad problemet er, den sande kerne kunne være at forsøge at identificere specifikt hvor fejlen opstår, identificere, hvad problemet er, og derefter fastsættelse det. Så giver dette som et eksempel af, hvad der kunne være noget at vi allerede kender, men kan blive begravet inden andre elementer i koden. Så åbner denne anden kilde kode fil som et eksempel, denne opdeling problem er nu en del af et større program. Stadig kan være lidt bit konstruerede, og vi kan være i stand til nemt identificere det, især da vi bare diskuterer dette. Men vi kan regne ud, at dette Problemet kan eksistere på en større skala. Hvis jeg kompilere dette, og nu køre den, skal du indtaste et ulige antal, Vi kan se, at vi ikke får præcis output, som vi måske have forventet. I dette særlige tilfælde, Vi kan sige, at vi vil tælle alle numrene fra en op til nogle specifikke nummer. Og vi kan se, at vi har en række spørgsmål her, hvis vi udsende, simpelthen, 0 og 1, når vi giver et input af 5. Så vi ved allerede, at der er et problem her. Men vi kan ikke vide præcist hvor dette spørgsmål rent faktisk eksisterer. Nu er en af ​​de måder, vi kan forsøge at løse dette er noget, som vi har allerede blevet introduceret til. Vi kan bare bruge det på en større skala. På linje 14, har vi denne printf funktion, som giver os mulighed for at udskrive staten af forskellige oplysninger. Og det er noget, du bør udnytte i dit program at forsøge at finde ud af præcis, hvad der er sker i forskellige linjer kode. Så selv om dette ikke er endelige output, at vi faktisk ønsker at producere ud af dette program, vi stadig kunne have nogle debug udsagn, hvor vi kan prøve at finde ud af præcis, hvad der sker inde i vores kode. Så i dette tilfælde, vil jeg printf med debug tag. I dette tilfælde er det bare en debug string at jeg er up-lægge, så det bliver meget klar i produktionen af ​​min kode hvad det er, at jeg ønsker at vise. Og output her nummeret at vi har beregnet. I dette tilfælde, jeg kunne ønsker at vide præcist hvad der sker før og efter nogle specifikke beregning. Så jeg kan bruge en printf før og efter denne linje kode. I dette tilfælde kunne jeg selv gøre det lidt mere klart ved at sige debug før og debug efter så at jeg ikke forveksle mig med flere linjer, der ser identiske. Nu, hvis vi kompilere dette og køre det, indtaste et nummer ligesom fem igen, Vi kan se, at vi har nu output før og efter og opdager, at vi ikke har gjort en klar division eller klar have af det antal at vi faktisk ønsker at gøre. Nu i dette tilfælde, det er egentlig ikke en klar output. Det er egentlig ikke et klart resultat, Vi vil ud af dette program. Og det er, igen, en lidt konstruerede. Men måske en af ​​de ting, vi kunne gøre, hvis specifikationen sagde at vi ønsker at dele dette ved 2 og tilføj 1-- så med andre ord, vi ønsker at runde up-- derefter vi måske vide, at vi kunne gøre det bestemt ting, i dette tilfælde. Nu her ved vi, at vi vil være i stand til at tilføje 1 til vores halveret nummer. Lad os genkompilere dette og bekræfte, at dette opfører den måde, som vi ønsker at. Vi kan se, at nu før have, har vi nummer 5. Efter at have, har vi tallet 3, som ifølge vores specifikationer, er, hvad vi ønskede at gøre. Men hvis vi ser på den output her, vi kan se, at vi kan have en anden bug helt, hvilket er at vi starter vores optælling fra 0. Nu igen, det er noget at vi har set tidligere og vi kan ordne ganske let. Men i dette tilfælde, vi havde også gavn for at bruge printf erklæring direkte inde i for-løkken at vide præcist, hvor Denne fejl foregik. Så printf udsagn er meget nyttige i at hjælpe du bestemme, hvor, netop i din kildekode, forekommer en specifik fejl. Og det er også vigtigt at indse at som vi skriver kode, vi måske have antagelser om status for et program. Eller vi kunne have antagelser hvad del af programmet er faktisk korrekt eller forkert, når senere som vi bygger på, at programmet og gøre det en del af en komplekse og større program at vi indser, at nogle aspekter af det er faktisk buggy. Brug printf kan virkelig hjælpe indsnævre og identificere regionerne et program, der måske ikke skal opføre sig præcis den måde, at vi forventer, baseret på vores antagelser. Men der er andre værktøjer til rådighed, samt, at tillade os at forsøge at figur ud af, hvor der sker en fejl og også specifikt hvilke ting der sker inde i programmet. Så ved hjælp af printf er meget nyttigt, når vi ønsker at identificere specifikke områder af et program, der har nogle fejl. Men bliver det også kedelige efter et stykke tid. I dette tilfælde er det en relativt simpelt program med blot en eller to variable. Og det bliver meget let for os at udskrive værdien af ​​disse variabler i forbindelse med større program. Men vi har måske en anden program, der har mange variable. Og det kan ikke være helt så let at bruge printf at forsøge at vurdere, hvad der sker til hver enkelt af disse variabler som programmet udfører. Der er et program, der findes kaldes en debugger program. I dette tilfælde den, som vi vil anvendelse er GNU debugger, eller GDB, der giver os mulighed for at inspicere det indre arbejdet i et program i en langt mere detaljeret måde. Vi kan faktisk udføre GDB fra kommandolinjen her ved blot at skrive GDB og kommando, som vi ønsker at debug. I dette tilfælde, ud. Nu i dette tilfælde, kan vi se, at det bringer os til en prompt, der siger GDB. Og vi kan faktisk udføre kommandoer til GDB til rent faktisk at begynde udførelse af program, stop det på visse punkter, evaluere variabler og inspicere variabler, findes i programmet tilstand på det pågældende tidspunkt, og så videre og så videre. Det giver en masse strøm til os. Men det bare så sker at CS50 IDE også giver en GUI eller en bruger interface til GDB at tillader os at gøre dette uden at behøve kommandolinjen overhovedet eller på alle selv. Den måde, at jeg kan få adgang til denne er ved hjælp af knappen debug på toppen af ​​CS50 IDE. Nu i fortiden, hvad vi har set, er, at vi bruger kommandoen line til at kompilere og derefter køre et program. Knappen debug gør begge disse trin. Men det også vil bringe op debugger fanen længst til højre der giver os mulighed for at inspicere en række egenskaber af programmet som det er at udføre. Hvis jeg klikker debug, i dette tilfælde vil det bringe op en ny fane i konsollen vinduet i bunden. Og du kan se, at denne fane har nogle oplysninger på toppen. Og vi kan stort set ignorere dette. Men en af ​​de ting at vi ønsker at lægge mærke til er, at det output det samme, som vi ville få, hvis vi forsøgte at køre gøre på C-programmet i terminalvinduet. Her kan vi se det kører klang, og det har en række flag, og det er at samle vores count.c fil, som var den valgte fane på tidspunktet at jeg ramte debug. Så det er meget nyttigt, fordi nu ved hjælp af denne debug knap, kan vi samtidig kompilere og derefter udføre programmet, at vi faktisk vil køre. Et af flagene, som er vigtigt i dette tilfælde, Vi har faktisk brugt i længst tid men også bare gjorde nogle hånd vinke [uhørligt], som er dette en lige her. I klang, det siger -ggdb3. I dette tilfælde, hvad vi er fortæller klang, vores compiler, er, at vi ønsker at kompilere vores program. Men også give hvad er kaldes symboloplysninger så compileren faktisk har adgang til en masse af de underliggende oplysninger indeholdt i programmet. Mere specifikt antal funktioner, som jeg har, navnene på disse funktioner, variablerne, typerne at disse variabler er, og en række andre ting, der hjælper debugger udføre sin funktion. Nu er der noget andet det er vigtigt at nævne når vi diskuterer kører et program på denne måde. Læg mærke til, at det har faktisk opdraget en ny fane i vores konsol langs bunden. Vi behøver ikke længere at interagere direkte med terminalvinduet. Men denne nye fane er faktisk et terminalvindue. Det netop er specifik for kørende program, som vi har skabt. Bemærk, at ved bunden, i kombination med nogle output ved clang compileren og GDB, som vi stort set bort, det faktisk viser outputtet af vores program i bunden. Nu er det vigtigt at indse, at denne ene vindue faktisk vil vise dig output fra dit program men også kan acceptere input for dette program, så godt. Så varsel, der siger angiv et tal, som er den samme udgang, som vi havde havde i terminalvinduet før. Men det er nu vist i denne nye fane. Jeg kan indtaste et nummer. Og det vil faktisk funktion som vi forventer viser os vores debug, output, output, der kan være fejlbehæftet, som vi har set før. Og i bunden, er det faktisk har nogle ekstra udgang fra BNP bare at sige, at dette program er afsluttet. Nu som du så i denne særlige løbe igennem, Det var ikke særlig nyttigt, fordi selv selvom vi havde kommet debugger menuen op, dette var stadig et kørende program. På intet tidspunkt gjorde det faktisk pause henrettelse for os at være i stand til at inspicere alle variablerne indeholdt deri. Der er noget andet at vi er nødt til at gøre for at få GDB at erkende, at vi ønsker at holde pause gennemførelse af programmet og ikke blot gør det muligt at fortsætte normalt som vi ville i alle andre tilfælde. For at holde pause udførelse, på nogle specifikke linje, vi nødt til at skabe, hvad der er kaldes en knækpunkt. Og en pause punkt er meget nemt oprettes i dette CS50 IDE ved at tage musen og klikke direkte til venstre af nogle specifikke linje nummer. Når jeg gør det, en rød prik vises, hvilket indikerer at denne linje er nu et knækpunkt. Og næste gang, jeg kører GDB, det vil stoppe udførelsen på dette knækpunkt når den når denne linje kode. Nu er dette er en vigtig ting at indse at det ikke nødvendigvis den tilfælde, at hver linje kode er faktisk tilgængelige. Hvis jeg skulle lave en funktion heroppe, for example-- tomrum F-- og bare gøre en udskrift linje her-- hej verden-hvis jeg aldrig kalde denne funktion, vil det være sådan, at hvis jeg sætte en pause punkt her, funktionen vil aldrig blive kaldt. Og derfor denne særlige knækpunkt vil faktisk aldrig pause gennemførelsen af ​​programmet. Så lad os sige, at jeg rigtigt skaber en pause punkt på nogle linje kode der rent faktisk vil blive henrettet. Nu i dette tilfælde, er dette den første linje i hovedfunktion. Så det vil helt sikkert være tilfældet at så snart jeg begynder udførelse, den allerførste linje vil blive nået. GDB vil holde pause udførelse. Og så vil jeg være i stand til interagere med debugger. Du kan indstille flere linjer som breakpoints, hvis du gerne vil. Vi kan også oprette en linje op her i dette segment af kode der aldrig vil blive nået. Og vi kan også indstille en yderligere nedenfor. Grunden til, at vi ville ønsker at gøre dette vi får gå ind i en lidt mere detalje i bare et øjeblik. Så for nu, lad mig bare deaktivere disse yderligere knækpunkter så vi kan se på, hvad der sker når jeg har en enkelt pause punkt i mit program. Jeg har lavet nogle ændringer til dette program. Så jeg har brug for at gemme det. Jeg vil klikke debug, så jeg kan begynde indsamling og derefter udførelse af debugger. Vi vil se, at, efter øjeblikke, de linje, vi valgt som pausen punkt er fremhævet med gult. Vi kan også se, at i øverst til højre i debug-panel at ikonet pause er vendt ind i en lille play-ikon. Det betyder, at vi har pause udførelse, i dette særlige tilfælde. Og rammer på knappen Afspil ville giver os mulighed for at genoptage udførelsen på det specifikke punkt. Bemærk, at der er et par andre knapper til rådighed i denne debug-panel, samt. Trin over, som tillader mig at udføre, at én linje kode og trin over til denne linje til næste, som i dette tilfælde, ville betyde, at printf sætningen udføres. Og det vil derefter pause udførelse på linje 13, som så. Og der er også et skridt i funktion, som er nyttigt, hvis jeg har skabt andre funktioner andre steder i kildekoden. Og jeg ønsker at træde ind disse funktioner snarere end udføre denne funktion som en helhed. Men vi vil se mere på trin i funktion i et øjeblik. Nu bemærke nogle andre ting, faktisk eksisterer inden for denne debug panel. Vi har dette panel kaldet kalder stakken, som viser os hvor præcis vi er. I dette tilfælde er vi inde af den primære funktion. Vores script kaldes count.c. Og vi tilfældigvis at være på linie 13, kolonne et, som er netop, hvad det fremhævede område af kildekoden angiver, samt. Nu opdager, at det også viser under den lokale variabel sektion alle de variabler, Der findes inden for denne funktion. Det er vigtigt at bemærke, at alle variabler vises i denne lokale variabel afsnit i en funktion, endnu før de er defineret. Vi kan se her, at vi har en variabel kaldte num, har en standardværdi på 0, og det er af typen int. Nu, før vi faktisk initialisere alle disse variabler, vi er ikke nødvendigvis garanteret at se en værdi på 0. Og afhængigt af andre henrettelser at du har udført og tilstanden af ​​din hukommelse, når du faktisk køre dette program, du måske opleve, at du kan ikke se værdier 0 og i stedet nogle andre skøre numre. Men du behøver ikke bekymre dig om det. Det kommer ikke til at være relevant, indtil du faktisk initialisere værdi. Nu i dette tilfælde, kan vi se, at Jeg har udført nogle udgange. Og jeg, lige nu, pause udførelse. Men i dette tilfælde, hvad Jeg virkelig ønsker at gøre er nu træde over denne linje af kode, så jeg kan faktisk forespørge brugeren om, at int, der vi vil bruge i vores program. Nu i denne sag, når Jeg ramte trin over, varsel at Pause eller rettere Genoptag Knappen er ændret til denne pause fordi denne kode er faktisk bliver kørt. Hvad sker der lige nu er, at det er venter os at indtaste nogle oplysninger som vi kan se af vores output tekst i bunden. Så lige nu, det er faktisk ikke sat på pause, selv om det, slags, vises at være, fordi der ikke sker noget. Men det bare så sker det, at i mit konkrete tilfælde på linje 13, Jeg venter på brugerinput. Og så GDB er ikke i stand til at inspicere et program, som det kører. Nu næste gang, jeg indtaste nogle input-- så jeg vil indtaste dette nummer 5, som vi har set i past-- ramt Return, og vi meddele, at straks, GDB pauser og igen, fremhæver den næste linje. Men se, at nu, som en resultat af vores indtastning af en værdi, Vi har opdateret denne værdi inde af vores lokale variable, som er meget nyttigt at vide nøjagtigt hvad dette nummer var i hukommelsen. Nu kan jeg tillade dette program til at fortsætte spille indtil udgangen af ​​dens udførelse ved at trykke på Genoptag. Vi kan se, at meget hurtigt gør programmet færdig udfører med samme output, som vi havde før, debugger lukker, og nu dette program er stoppet helt. I viser, at kun for henblik på at se, hvad der sker, når vi rent faktisk ramt Genoptag. Men vi faktisk kommer til at ønsker at gå tilbage til dette program så vi kan forsøge at debug præcist, hvad der sker. Nu, hvor jeg bruger debugger, kan jeg ikke brug for disse debug printf udsagn. Så jeg kunne fjerne dem, som jeg vil gøre nu bare at gå tilbage til vores enklere kode at vi havde et øjeblik siden. Nu når jeg gemmer programmere og udføre det, det vil igen gå til, at de første bryde punkt, som jeg havde på linje 11. Og jeg vil være i stand til at inspicere mine variabler som jeg ønsker at gøre. Det bare så sker det, at dette del ikke er meget interessant, Og jeg ved, at jeg har tænkt mig at udskrive denne erklæring. Indtast venligst et tal. Og så ved jeg, at jeg har tænkt mig at bede brugeren om at heltal. Så måske, jeg rent faktisk ønsker at flytte min bryde punkt lidt længere nede. Du kan fjerne break points ved at klikke igen, direkte til venstre for den linie nummer. Det røde prik forsvinder, hvilket indikerer at det knækpunkt nu er væk. Nu i denne sag, henrettelse er blevet sat på pause. Og så er det faktisk ikke kommer til at genoptages i det pågældende tilfælde. Men jeg kan sætte en pause pege lidt senere. Og når jeg nu genoptage min kode, vil det fortsætte og fortælle meningen med det knækpunkt. Igen, jeg ramte Genoptag. Synes ikke som noget, der sker. Men det er fordi min kode venter på input. Jeg vil indtaste et nummer 5, tryk Enter, og nu det næste brudpunkt vil blive ramt. Nu i dette tilfælde, er dette er linje kode at før, vi vidste tilfældigvis buggy. Så lad os vurdere, hvad der sker på dette særlige tidspunkt. Når en linie er markeret, linje er endnu ikke blevet henrettet. Så i dette tilfælde, kan vi se at jeg har et nummer, som Jeg har et heltal kaldet num, der har en værdi 5. Og jeg har tænkt mig til at optræde del matematik på dette nummer. Hvis jeg træde over det, vi kan bemærke, at værdien for num har ændret sig i overensstemmelse med aritmetiske, at vi faktisk har gjort. Og nu hvor vi er inde i denne for-løkke eller nu, at for-løkken selv er fremhævet, vi se, at vi har en ny variabel kaldet i, at vil blive anvendt i denne for-løkke. Husk nu, før at jeg nævnte, at nogle gange er du kommer til at se en slags skøre numre som standard, før dette nummer eller at variablen er faktisk initialiseret. Vi kan se, at netop her i denne variabel kaldte jeg, som ikke har endnu ikke blevet initialiseret på tidspunktet for at fremhæve. Men vi kan se, at det har nogle tal at vi ikke ville faktisk forvente. Det er ok. Må ikke bekymre dig om det fordi vi har faktisk ikke initialiseret dette nummer, indtil jeg trin over denne linje, og værdien I er blevet initialiseret med værdien 1. Så at se, at det er faktisk tilfældet, lad os træde over. Vi kan nu se, at der linje er blevet henrettet. Og vi er nu at fremhæve denne printf linje. Og vi kan nu se, hvordan vores værdier i I og 3 har ændret sig over tid. Dette er meget nyttigt at gøre, i virkeligheden, er at træde over linjer gentagne gange. Og du kan finde, hvad der faktisk sker inde i din for-løkke og hvad der sker med variabler inde i denne for-løkke som dette program henrettelse opstår et skridt ad gangen. Nu på dette punkt, jeg styrke over lige nok at jeg nu er ved afslutningen af ​​mit program. Hvis jeg træder over det, vil det faktisk ophøre henrettelse som vi har set tidligere. Lad mig starte denne, endnu en gang, så at jeg kan pege noget andet ud, samt. I dette tilfælde er det nu spørger mig, igen, for et nummer, der Jeg vil igen komme ind. Men denne gang, jeg har tænkt mig at komme ind i et større antal, så for-løkken vil gentage flere gange. I dette tilfælde, vil jeg at indtaste en værdi på 11. Nu igen, fordi jeg ville sætte en pause punkt linje 15, det kommer til at fremhæve denne linje. Vi kan se, at vores nummer 11 er korrekt repræsenteret i vores lokale variable. Stepping over det, vi kan nu se hvad der sker med vores værdi af i Når vi fortsætter inde i denne for-løkken. Det får øges hver gang vi nå toppen af ​​denne for-løkken. Nu er en af ​​de ting, der kan være nyttigt at gøre under udførelse med dette program er for mig at der faktisk ændre variabler midstream at se hvad der sker med mit program. I dette tilfælde kan jeg faktisk dobbeltklikke på værdien. Bemærk, at det bliver et tekstfelt. Nu kan jeg komme ind forskellige helt værdsætter at se, hvordan mit program opfører sig når jeg har ændret denne variabel. Nu i dette tilfælde den variable I indeholder nu værdien 10. Men programmet er stadig pause i udførelsen. Når jeg trin over, ser jeg, at den værdi i, som jeg indtastes som 10, ikke er større end værdien af ​​num, som straks medfører for-løkken at stoppe udførelsen. Nu det er ikke den eneste grunden til, at du ville vil ændre variablen på plads. Du kan faktisk ønsker at forsøge at ændre det, så at du kan fortsætte udførelse af en løkke eller så du kan ændre en vis værdi, før det når nogle specifikke sæt aritmetiske at du er ved at udføre. Så nu, at vi faktisk ændre værdi i som programmet blev udføre, det forårsagede for-løkken til at holde op tidligt fordi, lige pludselig, jeg sket at være større end værdien af num, således, at denne for-løkke ikke længere er brug for at blive henrettet. Endvidere er det tilfældigvis sådan, at vi ændret værdien af ​​i når linien 17 blev fremhævet, som var det tidspunkt at for-løkken udførelse faktisk blive evalueret. Hvis jeg havde ændret værdien af i på en anden linje, siger 19, vi ville have set anderledes adfærd, fordi linje 19 ville har udført før løkken tilstand blev revurderet. Nu på dette punkt, jeg er, igen, ved afslutningen af ​​dette program. Og jeg kan lade dette gå videre til lade mit program til at holde op naturligt. Men der er et par ting der er vigtige at tage væk fra dette særlige diskussion. Du er nødt til at evaluere dine egne antagelser om, hvordan koden skal opføre sig. Hver gang du tror, ​​at nogle stykke af kode, du kender tilfældigvis arbejde, der kan være et rødt flag til at gå tilbage og evaluere, og være sikker på at din antagelse om hvordan denne kode fungerer er faktisk rigtigt, at hvordan det er udtrykt i din kildekode. Men endnu mere at punkt var, når vi bruger debugger, du kan sætte breakpoints på forskellige linjer kode, hvilket vil medføre, at debugger til pause udførelse på hver af disse linjer så du kan evaluere hukommelse eller endda ændre det på plads. Og igen, husk, at du kan oprette flere breakpoints, så du kan også genoptage udførelse, springe over store dele af koden, og det vil automatisk holde pause ved næste knækpunkt. Der er faktisk mere avanceret funktioner i debugger, så godt. Men vi bliver nødt til at henvise dig til nogle efterfølgende videoer for virkelig at drille hinanden, hvordan at bruge disse særlige funktioner. For nu, tak meget til at se. Og held og lykke debugging.