[? DAN ARMADARAS:?] Hei, Jeg er [? Dan Armadaras?]. I dag skal vi være ute på feilsøking. Ikke bare skal vi snakke om noen teknikker, men også vi kommer til å se på noen av funksjonene som finnes innenfor CS50 IDE som tillater du enkelt kan feilsøke et program. Bare ett eksempel av noe som kan gå galt og det er faktisk noe som vi allerede har sett før. I dette tilfelle, er dette en C-program som aksepterer et heltall fra brukeren, deler den med to, og gir utgangen tilbake til brukeren. Nå fra hva vi har sett tidligere i forelesninger, vi vet at dette faktisk vil føre til bestemte typer divisjon problemer når vi har oddetall. Konkret vil vi bare kaste bort noe etter desimaltegnet. Nå vet vi at dette skjer for å være tilfelle. Og hvis vi kjøre den, kan vi bekrefte våre mistanker, først ved kompilering. Og så, ved å kjøre og skrive inn et oddetall. Dette er ikke noe nytt. Men dette er faktisk en eksempel på en bug som kan eksistere innenfor et større program som blir vanskeligere å spore opp. Selv om vi vet hva problemet er den sanne crux av saken kanskje prøver å identifisere spesielt der feilen oppstår, identifisere hva som er problemet er, og deretter fikse det. Så gi dette som et eksempel av hva som kan være noe som vi allerede kjenner, men kan bli begravet innenfor andre elementer i koden. Så åpner denne annen kilde kodefilen som et eksempel, denne divisjonen problemet nå en del av et større program. Fortsatt kan være litt litt contrived, og vi kan være i stand til å enkelt identifisere det, spesielt siden vi bare diskuterer dette. Men vi kan finne ut at dette Problemet kan ligge på en større skala. Hvis jeg kompilere dette og nå kjøre den, angir et oddetall, Vi kan se at vi ikke får nøyaktig utgangs at vi kan ha forventet. I dette spesielle tilfellet vi kan si at vi ønsker å telle alle tallene fra en opp til noen bestemt nummer. Og vi kan se at vi har en rekke problemer her hvis vi sender ut, rett og slett, 0 og en når vi gir en inngang på fem. Så vi vet allerede at det er et problem her. Men vi kan ikke vite nøyaktig hvor dette problemet faktisk eksisterer. Nå er en av måtene som vi kan prøve å fikse dette er noe som vi har allerede blitt presentert for. Vi kan bare bruke den på en større skala. På linje 14, har vi dette printf funksjon, som tillater oss å skrive ut staten av ulike typer informasjon. Og dette er noe som du bør utnytte i programmet for å prøve å finne ut nøyaktig hva som er skjer på ulike linjer med kode. Så selv om dette ikke er endelige resultatet at vi faktisk ønsker å produsere ut av dette programmet, vi fortsatt kanskje har noen debug setninger der vi kan prøve å finne ut nøyaktig hva som skjer inne i vår kode. Så i dette tilfellet, vil jeg printf med debug tag. I dette tilfelle, er denne bare en debug streng at jeg er opp-putting slik at det blir veldig klart i utgangen av min kode hva det er at jeg ønsker å vise. Og utgang her antall som vi har beregnet. I dette tilfellet, kan jeg ønsker å vite nøyaktig hva som skjer før og etter noen spesifikk beregning. Så jeg kan bruke en printf før og etter at kodelinje. I dette tilfellet kunne jeg selv gjøre det litt mer klart ved å si debug før og feilsøke etter så at jeg ikke forvirre meg selv med flere linjer som ser identiske. Nå hvis vi rekompilere dette og kjøre det, angir et nummer som fem igjen, Vi kan se at vi har nå produksjonen før og etter og finner ut at vi ikke har gjort en klar divisjon eller klart ha av antallet at vi faktisk ønsker å gjøre. Nå i dette tilfelle, er denne ikke egentlig en klar utgang. Det er egentlig ikke et klart utfall som vi ønsker ut av denne spesielle program. Og dette er, igjen, en litt contrived. Men, kanskje en av de tingene som vi kunne gjøre hvis spesifikasjonen sa at vi ønsker å dele dette med 2 og legge 1-- så med andre ord, vi ønsker å runde opp-- deretter vi kunne vite at vi kunne gjøre det bestemt ting, i dette tilfellet. Nå her vi vet at vi vil være legge en til vår halvert antall. La oss rekompilere dette og bekrefter at dette oppfører seg slik som vi vil. Vi kan se at nå før ha, har vi nummer fem. Etter å ha, har vi nummer tre, som i henhold til vår spesifikasjonen, er hva vi ønsket å gjøre. Men hvis vi ser på utgang her, kan vi se at vi kan ha en annen bug helt, noe som er at vi starter vår teller fra 0. Nå igjen, dette er noe som vi har sett i det siste og vi kan fikse ganske lett. Men i dette tilfellet, vi også hadde nytte for å bruke printf uttalelse direkte på innsiden av for loop å vite nøyaktig hvor at feilen var oppstått. Så printf uttalelser er svært nyttig i å hjelpe du bestemme hvor, nettopp i kildekoden, en spesifikk feil oppstår. Og det er også viktig å innse det, som vi skriver kode, vi kan ha forutsetninger om tilstanden i et program. Eller vi kan ha forutsetninger om hvilken del av programmet er faktisk riktig eller feil når senere som vi bygger videre på det programmet og gjøre det en del av en komplekse og større program at vi innser at noen aspekter av det er faktisk buggy. Ved hjelp av printf virkelig kan hjelpe innskrenke og identifisere regionene i et program som ikke kan skal oppføre seg akkurat slik at vi forventer, basert på våre antagelser. Men det er andre verktøy tilgjengelig, samt, som tillater oss å prøve å finne ut hvor en feil er oppstått Og også, spesifikt, hva ting skjer inne i programmet. Så bruker printf er veldig nyttig når vi ønsker for å identifisere spesifikke områder av et program som har noen bug. Men det blir også kjedelig etter en stund. I dette tilfelle, er dette en relativt enkelt program med bare én eller to variabler. Og blir det veldig enkelt for oss å skrive ut verdien av disse variablene i sammenheng med den større program. Men vi kan ha en annen program som har mange variabler. Og det er kanskje ikke helt så lett å bruke printf å forsøke å vurdere hva som skjer til hver og en av disse variablene som programmet utfører. Det er et program som eksisterer kalles en debugger program. I dette tilfellet, som vi vil bruk er GNU debugger, eller GDB, som tillater oss å inspisere den interne arbeidet i et program i en mye mer detaljert måte. Vi kan faktisk kjøre GDB fra kommandolinjen her ved å skrive GDB og kommando som vi ønsker å feilsøke. I dette tilfelle teller. Nå i dette tilfellet, kan vi se at det bringer oss til en melding som sier GDB. Og vi kan faktisk utføre kommandoer til GDB å faktisk begynne utførelsen av program, stoppe det på enkelte punkter, evaluere variablene og inspisere de variablene som finnes i programtilstand på det aktuelle tidspunktet, og så videre og så videre. Det gir mye makt til oss. Men det bare så skjer at CS50 IDE også gir et GUI eller en bruker grensesnitt for GDB som tillater oss å gjøre dette uten å måtte kommandolinjegrensesnittet hodet eller i det hele tatt enda. Den måten jeg kan få tilgang til er ved hjelp av debug-knappen på toppen av CS50 IDE. Nå i det siste, hva vi har sett er at vi bruker kommandoen linje for å kompilere og kjøre et program. Debug knapp gjør begge disse trinnene. Men det vil også få opp debugger fanen lengst til høyre som tillater oss å inspisere en rekke av egenskapene til det program som det blir utført. Hvis jeg klikker debug, i dette tilfelle, vil det gi opp en ny fane i konsollen vindu helt nederst. Og du kan se at denne kategorien har litt informasjon på toppen. Og vi kan i stor grad ignorere dette. Men en av de tingene at vi ønsker å legge merke til er at det utganger det samme som vi ville fått hvis vi prøvde å kjøre gjøre på C-program i terminalvinduet. Her kan vi se den kjører klang, og den har en rekke flagg, og det er å samle vår count.c fil, som var den valgte kategorien på tiden at jeg traff debug. Så dette er veldig nyttig fordi nå bruker denne debug-knappen, kan vi samtidig kompilere og deretter kjøre programmet at vi faktisk vil kjøre. En av de flagg som er viktig, i dette tilfellet vi har faktisk vært å bruke for lengst men også bare gjorde noen hånd vinke [uhørbart], som er dette en rett her. I klang, sier -ggdb3. I dette tilfellet, det vi forteller klang, vår kompilator, er at vi ønsker å kompilere programmet vårt. Men også gi hva er kalt symbolinformasjon slik at kompilatoren faktisk har tilgang til mye av den underliggende informasjon inneholdes i programmet. Mer spesielt er antallet av funksjoner som jeg har, navnene på disse funksjoner, variablene, hvilke typer at disse variabler er, og en rekke av andre ting som hjelper debugger utføre sin operasjon. Nå er det noe annet det er viktig å nevne når vi diskuterer løping et program på denne måten. Legg merke til at det har faktisk brakt opp en ny fane i vår konsoll langs bunnen. Vi trenger ikke lenger å samhandle direkte med terminalvinduet. Men denne nye kategorien er faktisk et terminalvindu. Det er bare bestemt til driften program som vi har skapt. Legg merke til at på bunnen, i kombinasjon med noen utgang av clang kompilatoren og GDB, som vi kan i stor grad ignorere, det faktisk viser resultatet av programmet vårt helt nederst. Nå er det viktig å innse at dette vinduet faktisk vil vise deg utgang fra programmet men også kan akseptere innspill for det program, samt. Så varsel som sier Skriv inn et tall, som er den samme produksjonen som vi hadde hadde i terminalvinduet før. Men det er nå vist i denne nye kategorien. Jeg kan legge inn et nummer. Og det vil faktisk funksjon som vi forventer viser oss våre feilsøke, utgang, utgang som kan være buggy, som vi har sett før. Og helt nederst, det faktisk har noen ekstra utgang fra BNP sier bare at dette programmet er fullført. Nå som du så i denne Spesielt kjøre gjennom, Det var ikke særlig nyttig fordi selv om vi hadde debugger menyen kommer opp, dette var likevel et kjørende program. Ikke på noe punkt gjorde det faktisk stanse henrettelsen for oss for å kunne inspisere hele variablene som finnes. Det er noe annet at vi må gjøre for å få GDB å erkjenne at vi ønsker for å stanse gjennomføringen av programmet og ikke bare tillate den å gå videre normalt som vi ville i alle andre tilfeller. For å stanse henrettelsen, på noen bestemt linje, vi trenger for å lage hva som er kalles et avbruddspunkt. Og en pause punkt er veldig enkelt laget i denne CS50 IDE ved å ta musen og klikke direkte til venstre av noen bestemt linjenummer. Når jeg gjør det, en rød prikk vises, noe som indikerer at den linjen er nå en pause punkt. Og neste gang jeg kjører GDB, det vil stoppe henrettelsen på det pause punkt når den når den kodelinje. Nå er dette en viktig ting å innse at det ikke nødvendigvis Ved at hver linje med kode er faktisk tilgjengelig. Hvis jeg skulle lage en funksjon her oppe, for example-- ugyldig f-- og bare gjøre en utskrift linje her-- hallo world-- om jeg aldri kalle denne funksjonen, vil det være slik at, hvis jeg setter en pause poeng her, funksjonen vil aldri bli kalt. Og derfor denne Særlig break point vil aldri stoppe gjennomføring av programmet. Så la oss si at jeg riktig opprette en pause punkt på noen linje med kode som faktisk vil bli henrettet. Nå i dette tilfellet, er dette første linje i hovedfunksjon. Så det vil sikkert være tilfelle at så snart jeg begynner gjennomføring, den aller første linjen vil bli nådd. GDB vil stanse henrettelsen. Og da vil jeg være i stand til å samhandle med debugger. Du kan stille inn flere linjer som breakpoints, hvis du ønsker. Vi kan også lage en linje opp her i dette segmentet av kode som aldri vil bli nådd. Og vi kan også opprette en nærmere nedenfor. Grunnen til at vi ville ønsker å gjøre dette vi vil gå inn i en litt mer detalj i bare et øyeblikk. Så for nå, la meg bare deaktivere disse ekstra brytepunkter slik at vi kan se på hva som skjer når jeg har en eneste pause punkt i mitt program. Jeg har gjort noen endringer i dette programmet. Så jeg trenger å lagre det. Jeg vil klikke debug slik at jeg kan begynne utarbeidelse og deretter gjennomføring av debugger. Vi vil se at etter øyeblikkene, de linje som vi valgt som pause punkt er markert med gult. Vi kan også legge merke til at i øverst til høyre i debug panel at pausen ikonet har slått inn litt lek ikon. Dette betyr at vi har pause utførelse, i dette spesielle tilfelle. Og trykket på play-knappen vil tillate oss å gjenoppta kjøring på det bestemt punkt. Legg merke til at det er et par andre knappene som er tilgjengelige i denne debug panel, også. Gå over, som tillater meg å utføre som en linje med kode og gå over til den linje til neste, som i dette tilfellet ville bety at printf setningen utføres. Og det vil deretter pause kjøring på linje 13, som så. Og det er også et skritt i funksjon, hvilken er nyttig hvis jeg har skapt andre funksjoner andre steder i kildekoden. Og jeg ønsker å gå inn disse funksjonene i stedet utføre som fungerer som en helhet. Men vi vil se mer på trinnet i funksjon i løpet av et øyeblikk. Nå merke noen andre ting som faktisk eksisterer innenfor denne debug panel. Vi har dette panelet kalles kaller stack, som viser oss hvor vi er. I dette tilfellet, er vi inne til hovedfunksjonen. Vår script kalles count.c. Og vi måtte være på linje 13, en kolonne, hvilken er nettopp hva den markerte regionen av kildekoden indikerer at, i tillegg. Nå merker at dette viser også under den lokale variable delen alle variablene som eksisterer innenfor denne funksjonen. Det er viktig å merke seg at alle variablene vises i denne lokal variabel seksjon innenfor en funksjon, til og med før de er definert. Vi ser her at vi har en variabel kalt num, har en standardverdi på 0, og det er av typen int. Nå før vi faktisk initial alle disse variablene, vi er ikke nødvendigvis garantert å se en verdi på 0. Og avhengig av andre henrettelser at du har utført og staten hukommelsen når du faktisk kjøre dette programmet, du kan finne det du ikke ser verdiene av 0 og, istedenfor, noen andre sprø tall. Men ikke bekymre deg om det. Det kommer ikke til å være relevant til du faktisk initial verdien. Nå i dette tilfellet, kan vi se at Jeg har gjort noen utganger. Og jeg, akkurat nå, stanset henrettelsen. Men i dette tilfelle, hva Jeg ønsker virkelig å gjøre er å nå gå over denne linjen av koden slik at jeg faktisk kan spørre brukeren for at int som vi ønsker å bruke i vårt program. Nå i dette tilfellet, når Jeg traff gå over, varsel at Pause eller snarere Resume knappen er endret til dette Pause-knappen fordi denne kode er faktisk utfører. Hva er det som skjer akkurat nå er at det er venter på oss for å legge inn litt informasjon som vi kan se av produksjonen vår tekst helt nederst. Så akkurat nå, er dette faktisk ikke stanset, selv om det, liksom, vises å være fordi ingenting skjer. Men det har seg slik at i min spesifikke saken på linje 13, Jeg venter på brukerundersøkelser. Og så GDB er ikke i stand til å inspisere et program som det er i gang. Nå neste gang jeg skriver noe input-- så jeg skal gå inn som nummer fem, som vi har sett i past-- hit Return, og vi Legg merke til at med en gang, GDB pauser og, igjen, understreker neste linje. Men legg merke til at nå, som en Resultatet av vår legge inn en verdi, Vi har oppdatert at verdien inne av våre lokale variabler, som er svært nyttig å vite nøyaktig hva det tallet var i minnet. Nå kan jeg tillate dette programmet til å fortsette spille til slutten av sin utførelse ved å treffe Resume. Vi kan se at svært raskt gjør programmet ferdig utførende med den samme produksjonen som vi hatt før, debugger lukkes, og nå dette programmet har stoppet helt. I viser at bare for formålene med å se hva skjer når vi faktisk treffer Resume. Men vi faktisk kommer til å ønsker å gå tilbake til dette programmet slik at vi kan prøve å feilsøke nøyaktig hva som skjer. Nå som jeg bruker debugger, kan jeg ikke trenger disse debug printf uttalelser. Så jeg kan flytte dem som jeg vil gjøre nå bare å gå tilbake til vår enklere kode at vi hadde et øyeblikk siden. Nå når jeg lagrer programmere og kjøre den, det vil, igjen, gå til den innledende bryte punktet at jeg hadde på linje 11. Og jeg skal være i stand til å inspisere mine variabler som jeg ønsker å gjøre. Det bare så skjer at denne del er ikke veldig interessant, Og jeg vet at jeg kommer å skrive ut denne uttalelsen. Vennligst skriv inn et nummer. Og så vet jeg at jeg kommer å spørre brukeren om at heltall. Så kanskje jeg faktisk ønsker å flytte min bryte punkt litt lenger ned. Du kan fjerne break poeng ved å klikke igjen, direkte til venstre for denne linjen nummer. Det røde prikken forsvinner, indikerer at det knekkpunktet er nå borte. Nå i dette tilfellet henrettelsen er midlertidig stoppet. Og så det er ikke faktisk kommer til å fortsette i det aktuelle tilfellet. Men jeg kan sette en pause peke litt senere. Og når jeg nå gjenoppta min kode, vil den fortsette og fortelle poenget med at knekkpunktet. Igjen, jeg traff Resume. Ser ikke ut som noe som skjer. Men det er fordi min kode venter på inngangen. Jeg vil legge inn et nummer fem, trykk Enter, og nå neste break point vil bli rammet. Nå i dette tilfelle denne er linjen med kode det, før vi visste tilfeldigvis buggy. Så la oss vurdere hva som skjer på dette spesielle tidspunktet. Når en linje er uthevet, dette linje har ennå ikke blitt utført. Så i dette tilfellet, kan vi se at jeg har et nummer, som Jeg har et heltall kalles num som har en verdi 5. Og jeg kommer til å være utøvende litt matematikk på dette nummeret. Hvis jeg gå over det, kan vi Legg merke til at verdien for num er endret i henhold til aritmetikk at vi faktisk har gjort. Og nå som vi er innsiden av denne for loop eller nå som for loop selv er markert, vi ser at vi har en ny variabel kalt jeg at kommer til å bli brukt i den for loop. Nå husker før at jeg nevnt at noen ganger du er kommer til å se en slags gal numre som standard før det nummeret eller at variabelen er faktisk initialisert. Vi kan se at nettopp her i denne variabelen heter jeg, som ikke har ennå ikke blitt initialisert ved å fremheve. Men vi kan se at det har noen tall at vi ikke ville faktisk forvente. Det er greit. Ikke bry deg om det fordi vi har faktisk ikke initialisert det nummeret før jeg gå over denne linjen og verdien Jeg har blitt initialisert til verdien 1. Så for å se at det er faktisk tilfelle, la oss gå over. Vi kan nå se at det linjen har blitt henrettet. Og vi er nå fremhever dette printf linje. Og vi kan nå se hvordan våre verdier av jeg og 3 har endret seg over tid. Dette er svært nyttig å gjøre, faktisk, er å gå over linjene flere ganger. Og du kan finne hva som faktisk skjer innsiden av for loop og hva som skjer med variabler inne på at for loop som at programmet kjøres oppstår ett skritt om gangen. Nå på dette punktet, jeg tråkket over akkurat nok at jeg nå er på slutten av mitt program. Hvis jeg gå over det, vil det faktisk opphøre henrettelse som vi har sett i det siste. La meg starte dette, enda en gang, så at jeg kan peke noe annet ut, også. I dette tilfelle er det nå spør meg igjen, for et tall, som Jeg vil, igjen, gå inn. Men denne gangen kommer jeg til å gå inn i et større antall, slik at for loop vil reagere flere ganger. I dette tilfellet, jeg kommer å angi en verdi av 11. Nå igjen fordi jeg hadde satt en pause punkt på linje 15, det kommer til å markere den linjen. Vi kan se at vår nummer 11 er riktig representert i våre lokale variabler. Tråkke over at vi kan nå se hva som skjer til vår verdi i når vi fortsetter på innsiden av denne for sløyfen. Det blir økes hver gang vi når toppen av det for loop. Nå er en av de tingene som kanskje være nyttig å gjøre under utførelse med dette programmet er for meg å faktisk endre variabler midtstrøms å se hva som skjer med mitt program. I dette tilfellet kan jeg faktisk Dobbeltklikk verdien. Legg merke til at det blir et tekstfelt. Nå kan jeg skrive annerledes verds helt for å se hvordan mitt program oppfører seg når jeg har endret den variabelen. Nå i dette tilfellet, den variable jeg nå inneholder verdien 10. Men programmet er fremdeles pauset i kjøring. Når jeg går over, jeg ser at verdi i, som jeg skrev som 10, ikke er større enn verdien av num, som umiddelbart fører til at for loop å stoppe gjennomføring. Nå det er ikke den eneste Grunnen til at du ville ønsker å endre den variable på plass. Du kan faktisk ønsker for å prøve å endre det slik at du kan fortsette utførelse av en løkke eller slik at du kan endre noen verdi før det når noen bestemt sett av aritmetiske at du er i ferd med å utføre. Så nå som vi faktisk endre Verdien av jeg så programmet ble utførende, det forårsaket for loop å slutte tidlig på grunn, plutselig, jeg skjedde til å være større enn verdien av num, noe som betyr at det for loop ikke lenger nødvendig å bli henrettet. Videre skjedde det å være Ved at vi endret verdien av jeg når linjen 17 ble fremhevet, som var poenget i tid at for loop kjøring ble faktisk blir evaluert. Hvis jeg hadde endret verdien av jeg på en annen linje, sier 19, vi ville ha sett annerledes atferd fordi linje 19 ville har utført før løkken Tilstanden ble revurdert. Nå på dette punktet, er jeg, igjen, ved slutten av dette programmet. Og jeg kan la dette fortsette til tillate mitt program til å avslutte naturlig. Men det er et par ting som er viktig å ta bort fra denne diskusjonen. Du må vurdere dine egne forutsetninger om hvordan koden skal oppføre seg. Hver gang du tror at noen stykke av koden du vet skjer til å arbeide, som kan være et rødt flagg for å gå tilbake og vurdere, og sørg at forutsetningen om hvordan koden fungerer er faktisk sant til hvordan det er uttrykt i kildekoden. Men enda mer til poenget var, når vi bruker debugger, du kan sette stoppunkter på ulike linjer med kode, noe som vil føre til at debugger til pause utførelse ved hver av disse linjer slik at du kan evaluere minne eller endre det på plass. Og igjen, husk at du kan opprette flere stoppunkter, slik at du kan også gjenoppta kjøring, hopp over store deler av koden, og det vil automatisk pause ved neste pause punkt. Det er faktisk mer avansert funksjonene i debugger, så vel. Men vi må henvise deg til noen påfølgende videoer for å virkelig erte hverandre hvordan å bruke de bestemte funksjoner. For nå, takk veldig mye for å se på. Og lykke debugging.