1 00:00:00,000 --> 00:00:02,730 [Powered by Google Translate] [AVSNITT 5: mindre bekväm] 2 00:00:02,730 --> 00:00:05,180 [Nate Hardison, Harvard University] 3 00:00:05,180 --> 00:00:08,260 [Detta är CS50.] [CS50.TV] 4 00:00:08,260 --> 00:00:11,690 Så välkommen tillbaka, grabbar. 5 00:00:11,690 --> 00:00:16,320 Välkommen till avsnitt 5. 6 00:00:16,320 --> 00:00:20,220 Vid denna punkt, efter att ha avslutat quiz 0 och efter att ha sett hur du har gjort, 7 00:00:20,220 --> 00:00:25,770 förhoppningsvis du känner riktigt bra eftersom jag var mycket imponerad av poängen i detta avsnitt. 8 00:00:25,770 --> 00:00:28,050 För våra online tittare, vi har haft ett par frågor 9 00:00:28,050 --> 00:00:33,680 om de sista två problemen på problemet set - eller på frågesport, snarare. 10 00:00:33,680 --> 00:00:39,690 Så vi kommer att gå över dem verkligen snabbt så att alla ser vad som hände 11 00:00:39,690 --> 00:00:45,060 och hur man ska gå igenom den faktiska lösning snarare än bara tittar själva lösningen. 12 00:00:45,060 --> 00:00:50,330 Vi kommer att gå under de senaste par problem verkligen snabbt, 32 och 33. 13 00:00:50,330 --> 00:00:53,240 Bara återigen, så att online tittarna se detta. 14 00:00:53,240 --> 00:00:59,080 >> Om du vänder dig till ditt problem 32, som finns på sidan 13, 15 00:00:59,080 --> 00:01:02,730 13 av 16, är problemet 32 ​​handlar om swappar. 16 00:01:02,730 --> 00:01:05,010 Det handlade om att byta två heltal. 17 00:01:05,010 --> 00:01:08,740 Det är problem som vi hade gått över ett par gånger i föreläsningen. 18 00:01:08,740 --> 00:01:13,590 Och här, vad vi ber dig att göra är en sammanfattning av minne spår. 19 00:01:13,590 --> 00:01:17,000 Att fylla i värdena på variablerna som de är på stacken 20 00:01:17,000 --> 00:01:20,250 som koden går igenom denna swap funktion. 21 00:01:20,250 --> 00:01:24,500 I synnerhet vad vi tittar på - jag kommer att sätta detta iPad ned - 22 00:01:24,500 --> 00:01:29,650 i synnerhet, vad vi tittar på är denna linje numrerade 6 här. 23 00:01:29,650 --> 00:01:36,740 Och det är numrerade 6 för bara omedelbar närhet med föregående problemet. 24 00:01:36,740 --> 00:01:41,720 Vad vi vill göra är att visa eller märka tillstånd minnet 25 00:01:41,720 --> 00:01:46,090 eftersom det är vid den tidpunkt när vi utför denna linje nummer 6, 26 00:01:46,090 --> 00:01:52,540 vilket i själva verket är en återgång från vår swap-funktion här. 27 00:01:52,540 --> 00:01:59,450 Om vi ​​rulla ner hit såg vi att adresserna på allt i minnet lämnades för oss. 28 00:01:59,450 --> 00:02:02,540 Detta är mycket viktig, vi kommer tillbaka till det på bara ett ögonblick. 29 00:02:02,540 --> 00:02:09,240 Och sedan ner här på botten, hade vi en liten minne diagram som vi kommer att hänvisa till. 30 00:02:09,240 --> 00:02:12,490 Jag har faktiskt gjort detta på min iPad. 31 00:02:12,490 --> 00:02:20,720 Så jag ska alternera fram och tillbaka mellan iPad och denna kod bara som referens. 32 00:02:20,720 --> 00:02:26,540 >> Låt oss börja. Först, låt oss fokusera på den första par rader viktigaste här. 33 00:02:26,540 --> 00:02:30,220 Till att börja, vi kommer att initiera x till 1 och y till 2. 34 00:02:30,220 --> 00:02:33,040 Så vi har två heltalsvariabler, de är båda kommer att placeras på stacken. 35 00:02:33,040 --> 00:02:36,050 Vi ska sätta en 1 och en 2 i dem. 36 00:02:36,050 --> 00:02:43,150 Så om jag vänder över till min iPad, förhoppningsvis, låt oss se - 37 00:02:43,150 --> 00:02:48,660 Apple TV spegling, och där vi går. Okej. 38 00:02:48,660 --> 00:02:51,670 Så om jag vänder över till min iPad, 39 00:02:51,670 --> 00:02:56,220 Jag vill initiera x till 1 och y till 2. 40 00:02:56,220 --> 00:03:00,580 Vi gör det helt enkelt genom att skriva en 1 i rutan X 41 00:03:00,580 --> 00:03:07,730 och en 2 i rutan Y. Ganska enkel. 42 00:03:07,730 --> 00:03:11,620 Så låt oss nu gå tillbaka till den bärbara datorn, se vad som händer härnäst. 43 00:03:11,620 --> 00:03:15,810 Så detta nästa rad är där det blir knepigt. 44 00:03:15,810 --> 00:03:28,110 Vi passerar adress x och adress y som parametrarna a och b till swap-funktionen. 45 00:03:28,110 --> 00:03:32,380 Adressen x och adressen till y är saker som vi inte kan beräkna 46 00:03:32,380 --> 00:03:36,360 utan att hänvisa till dessa punktlistor just här nere. 47 00:03:36,360 --> 00:03:39,750 Och lyckligtvis de första två punktlistor berätta exakt vad svaren är. 48 00:03:39,750 --> 00:03:44,740 Adressen för x i minnet är 10, och adressen av y i minnet är 14. 49 00:03:44,740 --> 00:03:51,870 Så de är de värden som får skickas in som a och b uppe i vår swap-funktion. 50 00:03:51,870 --> 00:04:00,760 Så återigen, byta tillbaka till vår diagrammet, kan jag skriva en 10 i en 51 00:04:00,760 --> 00:04:07,400 och en 14 i b. 52 00:04:07,400 --> 00:04:11,610 Nu är denna punkt där vi vidare med swappen. 53 00:04:11,610 --> 00:04:14,520 Så vända tillbaka till den bärbara datorn igen, 54 00:04:14,520 --> 00:04:21,079 Vi ser att det sätt swappen fungerar är jag först dereference en och lagra resultatet i tmp. 55 00:04:21,079 --> 00:04:27,650 Så dereference operatören säger, "Hej. Behandla innehållet i variabel A som en adress. 56 00:04:27,650 --> 00:04:33,830 Gå till allt som lagras på den adressen, och ladda den. " 57 00:04:33,830 --> 00:04:41,720 Vad du laddar ur variabeln kommer att lagras i vår TMP variabel. 58 00:04:41,720 --> 00:04:45,150 Vända tillbaka till iPad. 59 00:04:45,150 --> 00:04:51,690 Om vi ​​går att lösa 10 vet vi att adress 10 är varible x 60 00:04:51,690 --> 00:04:55,480 eftersom vi fick höra av vår punktsatsen att adressen för x i minnet är 10. 61 00:04:55,480 --> 00:05:00,180 Så vi kan åka dit, få värdet av det, vilket är 1, som vi ser på vår iPad, 62 00:05:00,180 --> 00:05:06,300 och ladda det till TMP. 63 00:05:06,300 --> 00:05:08,250 Återigen, detta är inte den slutliga innehållet. 64 00:05:08,250 --> 00:05:14,350 Vi kommer att gå igenom och vi får till vår slutliga tillstånd av programmet i slutet. 65 00:05:14,350 --> 00:05:17,210 Men just nu har vi värdet 1 lagras i tmp. 66 00:05:17,210 --> 00:05:19,210 >> Och det finns en snabb fråga här. 67 00:05:19,210 --> 00:05:23,980 [Alexander] Är dereference operatör - det är bara stjärnan mitt framför variabeln? 68 00:05:23,980 --> 00:05:27,600 >> Ja. Så dereference operatören, som vi vänder tillbaka till våra bärbara gång, 69 00:05:27,600 --> 00:05:33,780 är denna stjärna rakt framför. 70 00:05:33,780 --> 00:05:37,460 I den meningen är det - du kontrastera det med multiplikation operatören 71 00:05:37,460 --> 00:05:42,400 som kräver två saker, den dereference operatören är en unär operatör. 72 00:05:42,400 --> 00:05:46,130 Bara tillämpas på ett värde i motsats till en binär operator, 73 00:05:46,130 --> 00:05:48,810 där du ansöker till två olika värden. 74 00:05:48,810 --> 00:05:52,080 Så det är vad som händer i denna linje. 75 00:05:52,080 --> 00:05:58,390 Vi laddade värdet 1 och lagras den i vår tillfälliga heltalsvariabel. 76 00:05:58,390 --> 00:06:05,800 Nästa rad lagrar vi innehållet i B till - 77 00:06:05,800 --> 00:06:12,630 eller snarare lagrar vi innehållet att b pekar på den plats där en pekar på. 78 00:06:12,630 --> 00:06:17,690 Om vi ​​analyserar detta från höger till vänster, kommer vi att dereference b, 79 00:06:17,690 --> 00:06:23,580 vi kommer att ta itu med 14, kommer vi att ta tag i heltal som finns där, 80 00:06:23,580 --> 00:06:26,900 och då kommer vi att gå till adressen 10, 81 00:06:26,900 --> 00:06:34,240 och vi kommer att kasta resultatet av vårt dereference av b i det utrymmet. 82 00:06:34,240 --> 00:06:40,080 Vända tillbaka till vår iPad, där vi kan göra det lite mer konkret, 83 00:06:40,080 --> 00:06:44,070 det kan hjälpa om jag skriver siffrorna på alla adresser här. 84 00:06:44,070 --> 00:06:53,820 Så vi vet att vid y, vi är på adress 14, x på adress 10. 85 00:06:53,820 --> 00:07:00,180 När vi börjar på B, vi dereference B, kommer vi att ta värdet 2. 86 00:07:00,180 --> 00:07:08,320 Vi kommer att ta tag i detta värde eftersom det är det värde som bor på adress 14. 87 00:07:08,320 --> 00:07:15,700 Och vi kommer att sätta in den variabel som bor på adress 10, 88 00:07:15,700 --> 00:07:19,160 som är rätt där, motsvarande våra variabel x. 89 00:07:19,160 --> 00:07:21,810 Så vi kan göra lite för att skriva över här 90 00:07:21,810 --> 00:07:35,380 där vi bli av med våra 1 och i stället skriver vi en 2. 91 00:07:35,380 --> 00:07:39,560 Så alla är väl och gott i världen, trots att vi har överskrivna X nu. 92 00:07:39,560 --> 00:07:44,890 Vi har sparat x gamla värde i vårt TMP variabel. 93 00:07:44,890 --> 00:07:50,210 Så vi kan slutföra växlingen med nästa rad. 94 00:07:50,210 --> 00:07:53,030 Vända tillbaka till vår laptop. 95 00:07:53,030 --> 00:07:58,150 Nu återstår är att ta innehållet ur vår tillfälliga heltalsvariabel 96 00:07:58,150 --> 00:08:05,630 och lagra dem i den variabel som bor på den adress som b håller. 97 00:08:05,630 --> 00:08:10,230 Så vi kommer att effektivt dereference B för att få tillgång till variabeln 98 00:08:10,230 --> 00:08:14,340 som är den adress som b håller i det, 99 00:08:14,340 --> 00:08:19,190 och vi kommer att stoppa det värde som TMP håller i den. 100 00:08:19,190 --> 00:08:23,280 Vända tillbaka till IPAD gång. 101 00:08:23,280 --> 00:08:31,290 Jag kan radera detta värde här, 2, 102 00:08:31,290 --> 00:08:41,010 och istället ska vi kopiera 1 rakt in i det. 103 00:08:41,010 --> 00:08:43,059 Sedan nästa rad som kör, naturligtvis - 104 00:08:43,059 --> 00:08:47,150 Om vi ​​vänder tillbaka till den bärbara datorn - är detta 6, 105 00:08:47,150 --> 00:08:52,500 vilket är den punkt där vi ville ha vår diagrammet helt fylld ut. 106 00:08:52,500 --> 00:08:58,940 Så vända tillbaka till IPAD gång, bara så att du kan se det färdiga diagrammet, 107 00:08:58,940 --> 00:09:06,610 du kan se att vi har en 10 i en, en 14 i b, en 1 i tmp, en 2 i x, och en 1 i y. 108 00:09:06,610 --> 00:09:11,000 Finns det några frågor om detta? 109 00:09:11,000 --> 00:09:14,640 Gör detta mer meningsfullt att ha gått igenom det? 110 00:09:14,640 --> 00:09:24,850 Gör mindre betydelse? Förhoppningsvis inte. Okej. 111 00:09:24,850 --> 00:09:28,230 >> Pekare är ett mycket svårt ämne. 112 00:09:28,230 --> 00:09:33,420 En av killarna vi arbetar med har ett mycket vanligt talesätt: 113 00:09:33,420 --> 00:09:36,590 "För att förstå pekare, måste du först förstå pekare." 114 00:09:36,590 --> 00:09:40,530 Vilket jag tycker är väldigt sant. Det tar ett tag att vänja sig. 115 00:09:40,530 --> 00:09:45,360 Rita massor av bilder, drar massor av minne diagram som detta mycket bra, 116 00:09:45,360 --> 00:09:49,480 och efter att du går igenom exempel efter exempel efter exempel, 117 00:09:49,480 --> 00:09:54,450 det ska börja göra lite mer känsla och lite mer känsla och lite mer känsla. 118 00:09:54,450 --> 00:10:01,560 Slutligen, en dag kommer du ha allt helt behärskar. 119 00:10:01,560 --> 00:10:13,800 Eventuella frågor innan vi går vidare till nästa problem? Okej. 120 00:10:13,800 --> 00:10:18,840 Så vänder tillbaka till den bärbara datorn. 121 00:10:18,840 --> 00:10:23,300 Nästa problem vi har är problem nummer 33 på fil-I / O. 122 00:10:23,300 --> 00:10:26,350 Zooma in på detta lite. 123 00:10:26,350 --> 00:10:28,710 Problem 33 - Ja? 124 00:10:28,710 --> 00:10:32,110 >> [Daniel] Jag hade bara en snabb fråga. Denna stjärna eller asterisk, 125 00:10:32,110 --> 00:10:35,590 det kallas dereferencing när du använder en asterisk före. 126 00:10:35,590 --> 00:10:38,820 Vad kallas det när du använder et-tecken innan? 127 00:10:38,820 --> 00:10:43,140 >> Et-tecknet är före adress-av operatör. 128 00:10:43,140 --> 00:10:45,880 Så låt oss rulla tillbaka. 129 00:10:45,880 --> 00:10:49,310 Oops. Jag är i zoomläge så jag kan inte riktigt rulla. 130 00:10:49,310 --> 00:10:52,780 Om vi ​​tittar på den här koden verkligen snabbt just här, 131 00:10:52,780 --> 00:10:54,980 igen, samma sak händer. 132 00:10:54,980 --> 00:10:59,180 Om vi ​​tittar på den här koden här, på denna linje där vi ringa för att byta, 133 00:10:59,180 --> 00:11:10,460 et-tecknet är bara att säga "få den adress där variabel x liv." 134 00:11:10,460 --> 00:11:14,460 När din kompilator kompilerar koden, 135 00:11:14,460 --> 00:11:20,590 det har faktiskt fysiskt markera en plats i minnet för alla dina variabler att leva. 136 00:11:20,590 --> 00:11:24,910 Och så vad kompilatorn kan då göra när det sammanställs allt, 137 00:11:24,910 --> 00:11:31,110 den vet, "Åh, jag satte X på adressen 10. Jag satte y på adress 14." 138 00:11:31,110 --> 00:11:34,640 Den kan sedan fylla i dessa värden för dig. 139 00:11:34,640 --> 00:11:44,740 Så du kan då - det kan då passera detta och Pass & Y i också. 140 00:11:44,740 --> 00:11:50,730 Dessa killar få adressen, men också, när du passerar dem i swap-funktion, 141 00:11:50,730 --> 00:11:55,690 denna typ information här int * här, berättar kompilatorn, 142 00:11:55,690 --> 00:12:01,350 "Okej, vi kommer att tolka denna adress som en adress för en heltalsvariabel." 143 00:12:01,350 --> 00:12:05,900 Som en adress för en int, vilket skiljer sig från adressen för ett tecken variabel 144 00:12:05,900 --> 00:12:09,930 eftersom en int tar upp, på en 32-bitars maskin, tar upp 4 byte av utrymme, 145 00:12:09,930 --> 00:12:13,310 medan en karaktär tar bara upp 1 byte utrymme. 146 00:12:13,310 --> 00:12:17,310 Så det är viktigt att veta också vad som är - vad lever, vilken typ av värde 147 00:12:17,310 --> 00:12:20,340 bor på den adress som fick skickas in 148 00:12:20,340 --> 00:12:22,020 Eller den adress som du arbetar med. 149 00:12:22,020 --> 00:12:29,020 På så sätt vet du hur många byte av information att faktiskt ladda ur ditt RAM. 150 00:12:29,020 --> 00:12:31,780 Och sedan, ja, var det dereference operatör, som du frågar, 151 00:12:31,780 --> 00:12:37,200 går och hämtar information vid en speciell adress. 152 00:12:37,200 --> 00:12:42,820 Så står det, med denna variabel här, behandla innehållet i en som en adress, 153 00:12:42,820 --> 00:12:47,880 gå till den adressen och dra ut, ladda in i processorn, ladda in i ett register 154 00:12:47,880 --> 00:12:56,340 de faktiska värdena eller innehållet som lever på denna adress. 155 00:12:56,340 --> 00:12:59,620 Några fler frågor? Det är bra frågor. 156 00:12:59,620 --> 00:13:01,650 Det är en hel del ny terminologi också. 157 00:13:01,650 --> 00:13:09,800 Det är också typ av funky, se & och * på olika platser. 158 00:13:09,800 --> 00:13:13,180 >> Okej. 159 00:13:13,180 --> 00:13:18,530 Så tillbaka till problemet 33, fil I / O. 160 00:13:18,530 --> 00:13:22,540 Detta var en av de problem som jag tror ett par saker hände. 161 00:13:22,540 --> 00:13:25,400 Ett, det är en ganska ny tråd. 162 00:13:25,400 --> 00:13:30,590 Det presenterades ganska snart innan testet, 163 00:13:30,590 --> 00:13:33,400 och då tror jag att det var ungefär som en av de ord problem i matematik 164 00:13:33,400 --> 00:13:39,720 där de ger dig en hel del information, men du faktiskt inte sluta med att använda massor av det. 165 00:13:39,720 --> 00:13:44,060 Den första delen av detta problem beskriver vad en CSV-fil är. 166 00:13:44,060 --> 00:13:50,620 Nu en CSV-fil, enligt beskrivningen, är en kommaseparerad värden fil. 167 00:13:50,620 --> 00:13:55,300 Anledningen till att dessa är på alla intressanta, och anledningen du någonsin använda dem, 168 00:13:55,300 --> 00:14:00,800 är därför, hur många av er någonsin använt saker som Excel? 169 00:14:00,800 --> 00:14:03,240 Figur flesta av er har förmodligen kommer eller använda någon gång i ditt liv. 170 00:14:03,240 --> 00:14:06,430 Du kommer att använda något som Excel. 171 00:14:06,430 --> 00:14:10,940 För att få de uppgifter ur ett Excel-kalkylblad eller göra någon form av behandling med det, 172 00:14:10,940 --> 00:14:17,240 om du ville skriva en C-program eller Python program, Java-program, 173 00:14:17,240 --> 00:14:20,070 att ta itu med de data du har lagrat i det, 174 00:14:20,070 --> 00:14:23,170 en av de vanligaste sätten att få ut det i en CSV-fil. 175 00:14:23,170 --> 00:14:26,850 Och du kan öppna upp Excel och när du går till "Spara som" dialog, 176 00:14:26,850 --> 00:14:32,840 du kan få ut en verklig CSV-fil. 177 00:14:32,840 --> 00:14:35,890 >> Praktiskt att veta hur man ska hantera dessa saker. 178 00:14:35,890 --> 00:14:42,010 Så det fungerar är att det är liknande - jag menar, det imitera huvudsak ett kalkylblad, 179 00:14:42,010 --> 00:14:47,590 där, som vi ser här, i mycket längst till vänster stycke, 180 00:14:47,590 --> 00:14:49,910 Vi har alla efternamn. 181 00:14:49,910 --> 00:14:54,670 Så vi har Malan, sedan Hardison och sedan Bowden, MacWilliam och sedan Chan. 182 00:14:54,670 --> 00:14:59,470 Alla efternamn. Och sedan ett komma separerar de sista namnen från de första namnen. 183 00:14:59,470 --> 00:15:02,970 David, Nate, Rob, Tommy och Zamyla. 184 00:15:02,970 --> 00:15:06,850 Jag blandar alltid Robby och Tom. 185 00:15:06,850 --> 00:15:10,940 Och, slutligen, är den tredje kolumnen e-postadresser. 186 00:15:10,940 --> 00:15:18,500 När du förstår det, är resten av programmet ganska enkelt att genomföra. 187 00:15:18,500 --> 00:15:23,850 Vad vi har gjort för att efterlikna samma struktur i vårt C-program 188 00:15:23,850 --> 00:15:27,510 är att vi har använt en struktur. 189 00:15:27,510 --> 00:15:30,520 Vi börjar spela med dem lite mer också. 190 00:15:30,520 --> 00:15:35,790 Vi såg dem för första lite i problembild 3, när vi hade att göra med ordböcker. 191 00:15:35,790 --> 00:15:40,290 Men denna personal struct lagrar ett efternamn, ett förnamn och e-post. 192 00:15:40,290 --> 00:15:44,500 Precis som vår CSV-fil var förvaring. 193 00:15:44,500 --> 00:15:47,950 Så detta är bara konvertera från ett format till ett annat. 194 00:15:47,950 --> 00:15:54,630 Vi måste omvandla, i detta fall, en personal struct till en linje, 195 00:15:54,630 --> 00:15:59,060 en kommaseparerad linje, bara så där. 196 00:15:59,060 --> 00:16:01,500 Verkar det vettigt? Ni har alla tagit testet, 197 00:16:01,500 --> 00:16:07,680 så jag antar att du har åtminstone haft tid att tänka på detta. 198 00:16:07,680 --> 00:16:16,410 >> I hyra funktionen frågar problemet för oss att ta i - we'll zooma in på detta lite - 199 00:16:16,410 --> 00:16:22,480 ta i en personalstruktur, en personal struct, med namn s 200 00:16:22,480 --> 00:16:30,900 och bifoga dess innehåll till vår staff.csv fil. 201 00:16:30,900 --> 00:16:34,230 Det visar sig att det är ganska enkelt att använda. 202 00:16:34,230 --> 00:16:37,430 Vi kommer slags leka med dessa funktioner lite mer idag. 203 00:16:37,430 --> 00:16:44,510 Men i detta fall är fprintf funktion verkligen nyckeln. 204 00:16:44,510 --> 00:16:51,960 Så med fprintf kan vi skriva ut, precis som ni har använt printf hela denna term. 205 00:16:51,960 --> 00:16:55,050 Du kan printf en linje till en fil. 206 00:16:55,050 --> 00:16:59,030 Så istället för att bara göra vanliga printf samtalet där du ger den formatsträngen 207 00:16:59,030 --> 00:17:05,380 och sedan ersätta alla variabler med följande argument, 208 00:17:05,380 --> 00:17:11,290 med fprintf är din allra första argument istället den fil du vill skriva till. 209 00:17:11,290 --> 00:17:21,170 Om vi ​​skulle titta på detta i apparaten, till exempel, man fprintf, 210 00:17:21,170 --> 00:17:25,980 Vi kan se skillnaden mellan printf och fprintf. 211 00:17:25,980 --> 00:17:28,960 Jag zooma in här lite. 212 00:17:28,960 --> 00:17:33,140 Så med printf ger vi det en formatsträng, och sedan de efterföljande argumenten 213 00:17:33,140 --> 00:17:37,580 är alla variabler för utbyte eller ersättning i vår formatsträng. 214 00:17:37,580 --> 00:17:47,310 Medan med fprintf är det första argumentet verkligen den här filen * som kallas en ström. 215 00:17:47,310 --> 00:17:51,800 >> Flytta tillbaka hit till vår hyra, 216 00:17:51,800 --> 00:17:54,550 Vi har redan fått vår fil * ström öppnas för oss. 217 00:17:54,550 --> 00:17:57,810 Det är vad denna första raden gör, det öppnar staff.csv filen, 218 00:17:57,810 --> 00:18:01,690 öppnar den i append mode, och allt som är kvar för oss att göra är 219 00:18:01,690 --> 00:18:08,640 skriva personalstrukturen till filen. 220 00:18:08,640 --> 00:18:10,870 Och ska vi se, jag vill använda iPad? 221 00:18:10,870 --> 00:18:17,900 Jag kommer att använda iPad. Vi har ogiltig - låt oss sätta detta på bordet så jag kan skriva lite bättre - 222 00:18:17,900 --> 00:18:33,680 ogiltig hyra och det tar i ett argument, en personal struktur som kallas talet. 223 00:18:33,680 --> 00:18:44,120 Fick våra hängslen, vi har vår fil * heter filen, 224 00:18:44,120 --> 00:18:48,380 Vi har vår fopen linje som ges till oss, 225 00:18:48,380 --> 00:18:51,890 och jag ska bara skriva det som prickar eftersom det är redan i pedia. 226 00:18:51,890 --> 00:19:00,530 Och sedan på vår nästa rad, kommer vi att ringa ett samtal till fprintf 227 00:19:00,530 --> 00:19:03,700 och vi kommer att passera i den fil som vi vill skriva ut till, 228 00:19:03,700 --> 00:19:10,290 och sedan vår formatsträng, som - 229 00:19:10,290 --> 00:19:14,300 Jag ska låta er berätta hur det ser ut. 230 00:19:14,300 --> 00:19:20,500 Och du, Stella? Vet du vad den första delen av formatsträngen ser ut? 231 00:19:20,500 --> 00:19:24,270 [Stella] Jag är inte säker. >> Fråga gärna Jimmy. 232 00:19:24,270 --> 00:19:27,690 Vet du, Jimmy? 233 00:19:27,690 --> 00:19:31,000 [Jimmy] Skulle det vara bara förra? Jag vet inte. Jag är inte helt säker. 234 00:19:31,000 --> 00:19:39,020 >> Okej. Vad sägs om, fick någon få denna rätt på tentan? 235 00:19:39,020 --> 00:19:41,770 Nej Okej. 236 00:19:41,770 --> 00:19:47,920 Det visar sig att här allt vi behöver göra är att vi vill att varje del av vår personal struktur 237 00:19:47,920 --> 00:19:53,290 som ska skrivas ut som en sträng i vår fil. 238 00:19:53,290 --> 00:19:59,900 Vi använder bara strängen ersättning tecknet tre olika tillfällen eftersom vi har ett efternamn 239 00:19:59,900 --> 00:20:07,160 följt av kommatecken, då ett förnamn följt av ett kommatecken, 240 00:20:07,160 --> 00:20:12,430 och sedan slutligen den e-postadress som följs - vilket inte är 241 00:20:12,430 --> 00:20:15,140 montering på min skärm - men det följs av en radmatningstecken. 242 00:20:15,140 --> 00:20:20,060 Så jag kommer att skriva det bara där. 243 00:20:20,060 --> 00:20:23,560 Och sedan efter vår formatsträng, 244 00:20:23,560 --> 00:20:27,880 Vi har bara de substitutioner som vi åt med punktnotation 245 00:20:27,880 --> 00:20:31,370 som vi såg i problembild 3. 246 00:20:31,370 --> 00:20:48,820 Vi kan använda s.last, s.first och s.email 247 00:20:48,820 --> 00:20:58,990 att ersätta i de tre värden i vår formatsträng. 248 00:20:58,990 --> 00:21:06,190 Så hur gick det? Vettigt? 249 00:21:06,190 --> 00:21:09,700 Ja? Nej? Möjligen? Okej. 250 00:21:09,700 --> 00:21:14,180 >> Den sista sak som vi gör när vi har skrivit och efter att vi har öppnat vår fil: 251 00:21:14,180 --> 00:21:17,370 när vi har öppnat en fil, måste vi alltid komma ihåg att stänga den. 252 00:21:17,370 --> 00:21:19,430 Eftersom vi annars kommer att sluta läcka minnet, 253 00:21:19,430 --> 00:21:22,500 med upp fil deskriptorer. 254 00:21:22,500 --> 00:21:25,950 Så för att stänga den, vilket fungerar använder vi? Daniel? 255 00:21:25,950 --> 00:21:30,120 [Daniel] fclose? >> Fclose, exakt. 256 00:21:30,120 --> 00:21:37,520 Så den sista delen av detta problem var att ordentligt stänga filen, med hjälp av fclose funktionen 257 00:21:37,520 --> 00:21:40,370 som ser ut precis så. 258 00:21:40,370 --> 00:21:43,880 Inte för galet. 259 00:21:43,880 --> 00:21:46,990 Cool. 260 00:21:46,990 --> 00:21:49,520 Så det är problem 33 på testet. 261 00:21:49,520 --> 00:21:52,480 Vi kommer att ha definitivt mer I / O-kommer upp. 262 00:21:52,480 --> 00:21:55,130 Vi ska göra lite mer i föreläsning idag, eller i avsnitt idag, 263 00:21:55,130 --> 00:22:01,710 eftersom det är vad som kommer att bilda huvuddelen av denna kommande pset. 264 00:22:01,710 --> 00:22:05,020 Låt oss gå vidare från testet på denna punkt. Ja? 265 00:22:05,020 --> 00:22:10,880 >> [Charlotte]] Varför fclose (fil) i stället för fclose (staff.csv)? 266 00:22:10,880 --> 00:22:19,100 >> Ah. Eftersom det visar sig att - så frågan, som är en stor en, 267 00:22:19,100 --> 00:22:27,800 varför, när vi skriver fclose, vi skriver fclose (fil) stjärna variabel 268 00:22:27,800 --> 00:22:33,680 i motsats till filnamnet, staff.csv? Är det korrekt? Ja. 269 00:22:33,680 --> 00:22:39,570 Så låt oss ta en titt. Om jag byter tillbaka till min laptop, 270 00:22:39,570 --> 00:22:45,040 och låt oss titta på fclose funktionen. 271 00:22:45,040 --> 00:22:51,460 Så fclose funktionen stängs en ström och det tar i pekaren till bäcken som vi vill stänga, 272 00:22:51,460 --> 00:22:57,010 i motsats till den verkliga filnamnet som vi vill stänga. 273 00:22:57,010 --> 00:23:01,620 Och detta beror bakom kulisserna när du ringer till fopen, 274 00:23:01,620 --> 00:23:12,020 när du öppnar en fil, du fördela faktiskt minne för att lagra information om filen. 275 00:23:12,020 --> 00:23:16,380 Så du har filer pekare som har information om filen, 276 00:23:16,380 --> 00:23:23,080 som det är öppet, dess storlek, där du är just nu i filen, 277 00:23:23,080 --> 00:23:29,100 så att du kan göra läsa och skriva samtal till den platsen i filen. 278 00:23:29,100 --> 00:23:38,060 Du hamnar stänga pekaren istället för att stänga filnamnet. 279 00:23:38,060 --> 00:23:48,990 >> Ja? [Daniel] Så för att använda hyra, skulle du säga - hur går det få användaren ingång? 280 00:23:48,990 --> 00:23:53,830 Agerar som fprintf GetString i den meningen att det bara väntar på användarens inmatning 281 00:23:53,830 --> 00:23:57,180 och ber dig att skriva detta - eller vänta på dig att skriva dessa tre saker i? 282 00:23:57,180 --> 00:24:00,480 Eller behöver du använda något för att genomföra hyra? 283 00:24:00,480 --> 00:24:04,100 >> Ja. Så vi är inte - frågan var, hur vi får användarinmatning 284 00:24:04,100 --> 00:24:09,220 för att genomföra hyra? Och vad vi har här är den som ringer i hyra, 285 00:24:09,220 --> 00:24:17,690 antogs i denna personal struct med alla data som lagras i struct redan. 286 00:24:17,690 --> 00:24:22,990 Så fprintf kan bara skriva dessa data direkt till filen. 287 00:24:22,990 --> 00:24:25,690 Det finns ingen väntar på indata. 288 00:24:25,690 --> 00:24:32,110 Användaren har redan gett bidrag genom att korrekt sätta den i denna personal struct. 289 00:24:32,110 --> 00:24:36,510 Och saker, naturligtvis, skulle gå sönder om någon av dessa pekare var noll, 290 00:24:36,510 --> 00:24:40,370 så vi rullar tillbaka hit och vi ser på vår struct. 291 00:24:40,370 --> 00:24:43,640 Vi har sträng sist, sträng först sträng e-post. 292 00:24:43,640 --> 00:24:48,530 Vi vet nu att alla dessa verkligen, under huven, är char * variabler. 293 00:24:48,530 --> 00:24:53,470 Det kan eller inte kan peka till null. 294 00:24:53,470 --> 00:24:55,800 De kan peka på minne på högen, 295 00:24:55,800 --> 00:24:59,650 kanske minne på stacken. 296 00:24:59,650 --> 00:25:04,580 Vi vet inte riktigt, men om någon av dessa tips är noll, eller ogiltigt, 297 00:25:04,580 --> 00:25:08,120 att det definitivt kommer att krascha vår hyra funktion. 298 00:25:08,120 --> 00:25:11,050 Det var något som var lite utanför ramen för provet. 299 00:25:11,050 --> 00:25:16,440 Vi är inte oroande om det. 300 00:25:16,440 --> 00:25:22,170 Jättebra. Okej. Så gå vidare från testet. 301 00:25:22,170 --> 00:25:25,760 >> Låt oss avsluta den här killen, och vi kommer att titta på pset 4. 302 00:25:25,760 --> 00:25:34,700 Så om ni ser på pset spec, när du kan komma åt den, cs50.net/quizzes, 303 00:25:34,700 --> 00:25:42,730 Vi kommer att gå igenom några av avsnittet problem idag. 304 00:25:42,730 --> 00:25:52,240 Jag rulla ner - del frågor börjar på den tredje sidan av pset spec. 305 00:25:52,240 --> 00:25:57,800 Och den första delen ber dig att gå och titta på kort på omdirigera och rör. 306 00:25:57,800 --> 00:26:02,820 Som var typ av en cool kort, visar några nya, coola tricks kommandorad som du kan använda. 307 00:26:02,820 --> 00:26:06,050 Och sedan har vi ett par frågor till er också. 308 00:26:06,050 --> 00:26:10,860 Denna första fråga om strömmar, som printf skriver som standard, 309 00:26:10,860 --> 00:26:15,920 vi typ av berört bara lite för en stund sedan. 310 00:26:15,920 --> 00:26:22,380 Det fprintf att vi bara diskuterade tar i en fil * ström som argument. 311 00:26:22,380 --> 00:26:26,580 fclose tar i en fil * ström också, 312 00:26:26,580 --> 00:26:32,660 och avkastningen värdet av fopen ger en ström fil * också. 313 00:26:32,660 --> 00:26:36,060 Anledningen till att vi inte har sett dem förut när vi har behandlat printf 314 00:26:36,060 --> 00:26:39,450 beror printf har en standard ström. 315 00:26:39,450 --> 00:26:41,810 Och standard strömmen som den skriver 316 00:26:41,810 --> 00:26:45,190 hittar du reda på kort. 317 00:26:45,190 --> 00:26:50,080 Så definitivt ta en titt på det. 318 00:26:50,080 --> 00:26:53,010 >> I dagens avsnitt ska vi prata lite om GDB, 319 00:26:53,010 --> 00:26:57,720 eftersom mer bekant du är med det, desto mer praktik får du med det, 320 00:26:57,720 --> 00:27:01,390 desto bättre kan du vara att faktiskt jaga buggar i din egen kod. 321 00:27:01,390 --> 00:27:05,540 Detta påskyndar processen med felsökning upp enormt. 322 00:27:05,540 --> 00:27:09,230 Så genom att använda printf, varje gång du gör det du måste kompilera om koden, 323 00:27:09,230 --> 00:27:13,000 du måste köra det igen, ibland måste man flytta printf samtalet runt, 324 00:27:13,000 --> 00:27:17,100 kommentera ut kod, det tar bara ett tag. 325 00:27:17,100 --> 00:27:20,850 Vårt mål är att försöka övertyga dig om att med GDB kan du i huvudsak 326 00:27:20,850 --> 00:27:26,810 printf någonting när som helst i din kod och du behöver aldrig kompilera det. 327 00:27:26,810 --> 00:27:35,120 Du behöver aldrig starta och hålla gissa var man printf nästa. 328 00:27:35,120 --> 00:27:40,910 Det första du bör göra är att kopiera denna linje och få avsnittsmarkeringen bort av webben. 329 00:27:40,910 --> 00:27:47,530 Jag kopierar denna kodrad som säger, "wget ​​http://cdn.cs50.net". 330 00:27:47,530 --> 00:27:49,510 Jag ska kopiera den. 331 00:27:49,510 --> 00:27:55,950 Jag ska gå över till min apparat, zooma ut så att du kan se vad jag gör, 332 00:27:55,950 --> 00:28:01,890 klistra in den där, och när jag slog in, denna wget kommandot bokstavligen är ett webbaserat få. 333 00:28:01,890 --> 00:28:06,210 Det kommer att dra ner den här filen bort av Internet, 334 00:28:06,210 --> 00:28:11,790 och kommer rädda det aktuell katalog. 335 00:28:11,790 --> 00:28:21,630 Nu om jag lista min nuvarande katalogen kan du se att jag har denna section5.zip fil rätt där. 336 00:28:21,630 --> 00:28:25,260 Det sättet att hantera den där killen är att packa upp den, 337 00:28:25,260 --> 00:28:27,650 som du kan göra på kommandoraden, precis som här. 338 00:28:27,650 --> 00:28:31,880 Section5.zip. 339 00:28:31,880 --> 00:28:36,980 Det kommer packa upp den, skapa en mapp för mig, 340 00:28:36,980 --> 00:28:40,410 blåsa hela innehållet, lägg dem där. 341 00:28:40,410 --> 00:28:47,410 Så nu kan jag gå in i min avsnitt 5 katalog med kommandot cd. 342 00:28:47,410 --> 00:28:58,310 Rensa skärmen med tydlig. Så rensa skärmen. 343 00:28:58,310 --> 00:29:02,280 Nu har jag en trevlig ren terminal att ta itu med. 344 00:29:02,280 --> 00:29:06,200 >> Nu om jag lista alla filer som jag ser i den här katalogen, 345 00:29:06,200 --> 00:29:12,270 Ni ser att jag har fyra filer: buggy1, buggy2, buggy3 och buggy4. 346 00:29:12,270 --> 00:29:16,180 Jag har också fått motsvarande. C. filer. 347 00:29:16,180 --> 00:29:20,400 Vi kommer inte att titta på. C-filer för nu. 348 00:29:20,400 --> 00:29:24,140 Istället kommer vi att använda dem när vi öppnar upp GDB. 349 00:29:24,140 --> 00:29:28,220 Vi har hållit dem runt så att vi har tillgång till den aktuella källkoden när vi använder GDB, 350 00:29:28,220 --> 00:29:32,740 men målet för denna del av avsnittet är att mixtra runt med GDB 351 00:29:32,740 --> 00:29:40,370 och se hur vi kan använda den för att räkna ut vad som händer fel med var och en av dessa fyra buggy program. 352 00:29:40,370 --> 00:29:43,380 Så vi ska bara runt i rummet verkligen snabbt, 353 00:29:43,380 --> 00:29:47,000 och jag kommer att be någon att köra ett av de buggiga program, 354 00:29:47,000 --> 00:29:54,730 och sedan går vi som en grupp genom GDB, och vi får se vad vi kan göra för att åtgärda dessa program, 355 00:29:54,730 --> 00:29:58,460 eller åtminstone identifiera vad som händer fel i varje av dem. 356 00:29:58,460 --> 00:30:04,760 Låt oss börja här borta med Daniel. Kommer du köra buggy1? Låt oss se vad som händer. 357 00:30:04,760 --> 00:30:09,470 [Daniel] Det säger att det finns ett program fel. >> Ja. Exakt. 358 00:30:09,470 --> 00:30:12,460 Så om jag kör buggy1 får jag en seg fel. 359 00:30:12,460 --> 00:30:16,210 Vid denna punkt, jag kunde gå och öppna buggy1.c, 360 00:30:16,210 --> 00:30:19,450 försöka lista ut vad som går fel, 361 00:30:19,450 --> 00:30:22,000 men en av de mest motbjudande saker om detta segment fel fel 362 00:30:22,000 --> 00:30:27,610 är att det inte berätta om vad raden av programmets sakerna faktiskt gick fel och bröt. 363 00:30:27,610 --> 00:30:29,880 Du sorts måste titta på koden 364 00:30:29,880 --> 00:30:33,990 och räkna ut med gissning och kontrollera eller printf att se vad som går fel. 365 00:30:33,990 --> 00:30:37,840 En av de coolaste sakerna med GDB är att det är riktigt, riktigt enkelt 366 00:30:37,840 --> 00:30:42,170 att räkna ut den linje där ditt program kraschar. 367 00:30:42,170 --> 00:30:46,160 Det är helt värt det att använda den, även om det bara för att. 368 00:30:46,160 --> 00:30:56,190 Så för att starta upp GDB skriver jag GDB, och då jag ge den sökvägen till den körbara som jag vill köra. 369 00:30:56,190 --> 00:31:01,960 Här jag skriver gdb ./buggy1. 370 00:31:01,960 --> 00:31:06,600 Hit Enter. Ger mig all denna information om copyright, 371 00:31:06,600 --> 00:31:13,000 och här nere ser du denna linje som säger, "Läsa symboler från / home / 372 00:31:13,000 --> 00:31:17,680 jharvard/section5/buggy1. " 373 00:31:17,680 --> 00:31:22,060 Och om allt går bra, kommer du att se det skriva ut ett budskap som ser ut så här. 374 00:31:22,060 --> 00:31:25,500 Det ska läsa symboler, det ska säga "Jag läser symboler från körbar fil" 375 00:31:25,500 --> 00:31:29,900 och så kommer det att ha detta "gjort" budskap här. 376 00:31:29,900 --> 00:31:35,410 Om du ser någon annan variant av detta, eller om du ser att det inte kunde hitta de symboler 377 00:31:35,410 --> 00:31:41,460 eller något liknande, vad det betyder är att du bara inte har sammanställt din körbara ordentligt. 378 00:31:41,460 --> 00:31:49,980 När vi sammanställer program för användning med GDB måste vi använda den särskilda g flagga, 379 00:31:49,980 --> 00:31:54,540 och det är gjort som standard om du kompilerar dina program, bara genom att skriva att 380 00:31:54,540 --> 00:31:59,320 eller göra buggy eller göra återhämta någon av dessa. 381 00:31:59,320 --> 00:32:07,800 Men om du kompilera manuellt med klang, då måste du gå in och bland annat att-g flaggan. 382 00:32:07,800 --> 00:32:10,310 >> Vid denna punkt, nu när vi har vår GDB prompten 383 00:32:10,310 --> 00:32:12,310 det är ganska enkelt att köra programmet. 384 00:32:12,310 --> 00:32:19,740 Vi kan antingen skriva springa, eller så kan vi bara skriva r.. 385 00:32:19,740 --> 00:32:22,820 De flesta GDB kommandon kan förkortas. 386 00:32:22,820 --> 00:32:25,940 Vanligtvis bara en eller ett brev par, vilket är ganska trevligt. 387 00:32:25,940 --> 00:32:30,980 Så Saad, om du skriver r och trycker Enter, vad händer? 388 00:32:30,980 --> 00:32:39,390 [Saad] Jag har SIGSEGV, segmenteringsfel och sedan allt detta fikonspråk. 389 00:32:39,390 --> 00:32:43,650 >> Ja. 390 00:32:43,650 --> 00:32:47,990 Som vi ser på skärmen just nu, och som Saad sade, 391 00:32:47,990 --> 00:32:53,430 När vi skriver körning eller r och tryck Enter, får vi fortfarande samma seg fel. 392 00:32:53,430 --> 00:32:55,830 Så använder GDB löser inte vårt problem. 393 00:32:55,830 --> 00:32:59,120 Men det ger oss lite fikonspråk, och det visar sig att denna rappakalja 394 00:32:59,120 --> 00:33:03,080 faktiskt berättar om det händer. 395 00:33:03,080 --> 00:33:10,680 Att tolka detta lite, är detta första biten funktionen där allt händer fel. 396 00:33:10,680 --> 00:33:20,270 Det är detta __ strcmp_sse4_2, och det säger oss att det som händer i den här filen 397 00:33:20,270 --> 00:33:29,450 kallas sysdeps/i386, allt detta igen, typ av en enda röra - men linje 254. 398 00:33:29,450 --> 00:33:31,670 Det är typ av svårt att tolka. Vanligtvis när du ser sånt här, 399 00:33:31,670 --> 00:33:38,770 det betyder att det är seg förkastningar i en av systemets bibliotek. 400 00:33:38,770 --> 00:33:43,220 Så något att göra med strcmp. Ni har sett strcmp förut. 401 00:33:43,220 --> 00:33:52,730 Inte alltför galet, men betyder det att strcmp är trasig eller att det finns ett problem med strcmp? 402 00:33:52,730 --> 00:33:57,110 Vad tror du, Alexander? 403 00:33:57,110 --> 00:34:04,890 [Alexander] Är det - är 254 linjen? Och - inte binära, men det är inte deras tak, 404 00:34:04,890 --> 00:34:10,590 och sedan finns det ett annat språk för varje funktion. Är det 254 i den funktionen, eller -? 405 00:34:10,590 --> 00:34:21,460 >> Det är linje 254. Det ser ut som detta. Akt, så det är assemblerkod förmodligen. 406 00:34:21,460 --> 00:34:25,949 >> Men jag antar att det mer angelägen sak är, att vi har fått en seg fel, 407 00:34:25,949 --> 00:34:29,960 och det ser ut som det kommer från strcmp funktionen, 408 00:34:29,960 --> 00:34:38,030 innebär detta innebära, då är det strcmp sönder? 409 00:34:38,030 --> 00:34:42,290 Det bör inte, förhoppningsvis. Så bara för att du har ett segmenteringsfel 410 00:34:42,290 --> 00:34:49,480 i en av systemets funktioner innebär oftast att du bara inte har kallat det på rätt sätt. 411 00:34:49,480 --> 00:34:52,440 Det snabbaste du kan göra för att räkna ut vad som egentligen händer 412 00:34:52,440 --> 00:34:55,500 När du ser något galet så här, när du ser en seg fel, 413 00:34:55,500 --> 00:34:59,800 särskilt om du har ett program som är med mer än bara stora, 414 00:34:59,800 --> 00:35:03,570 är att använda en bakåtspårning. 415 00:35:03,570 --> 00:35:13,080 Jag förkorta bakåtspårning genom att skriva BT i motsats till den fullständiga bakåtspårning ordet. 416 00:35:13,080 --> 00:35:16,510 Men Charlotte, vad som händer när du skriver BT och tryck på Retur? 417 00:35:16,510 --> 00:35:23,200 [Charlotte] Det visar mig två linjer, linje 0 och linje 1. 418 00:35:23,200 --> 00:35:26,150 >> Ja. Så linje 0 och linje 1. 419 00:35:26,150 --> 00:35:34,560 Dessa är de verkliga stack ramar som var närvarande i spel när programmet kraschade. 420 00:35:34,560 --> 00:35:42,230 Med utgångspunkt från den översta ramen, ram 0 och gå till nedersta, som är ramen 1. 421 00:35:42,230 --> 00:35:45,140 Vår översta ramen är det strcmp ramen. 422 00:35:45,140 --> 00:35:50,080 Du kan tänka på detta som liknar det problemet vi bara gör på frågesport med pekare, 423 00:35:50,080 --> 00:35:54,890 där vi hade byta stack ram ovanpå viktigaste stack ram, 424 00:35:54,890 --> 00:35:59,700 och vi hade de variabler som swap använde ovanpå de variabler som huvudsakliga använde. 425 00:35:59,700 --> 00:36:08,440 Här vår krasch hände i vår strcmp funktion, som kallades av våra huvudsakliga funktion, 426 00:36:08,440 --> 00:36:14,370 och bakåtspårning ger oss inte bara de funktioner som saker misslyckades, 427 00:36:14,370 --> 00:36:16,440 men det är också berättar där allt kallades från. 428 00:36:16,440 --> 00:36:18,830 Så om jag rullar över lite mer åt höger, 429 00:36:18,830 --> 00:36:26,110 kan vi se att ja, vi var på rad 254 i detta strcmp-sse4.s fil. 430 00:36:26,110 --> 00:36:32,540 Men samtalet gjordes vid buggy1.c, linje 6. 431 00:36:32,540 --> 00:36:35,960 Så det betyder att vi kan göra - är att vi kan bara gå checka ut och se vad som pågick 432 00:36:35,960 --> 00:36:39,930 på buggy1.c, linje 6. 433 00:36:39,930 --> 00:36:43,780 Återigen finns det ett par sätt att göra detta. En är att avsluta från GDB 434 00:36:43,780 --> 00:36:49,460 eller har din kod öppnas i ett nytt fönster och korsreferens. 435 00:36:49,460 --> 00:36:54,740 Att i och för sig är ganska praktiskt för nu om du är på kontorstid 436 00:36:54,740 --> 00:36:57,220 och du har en seg fel och din TF är undrar var allt sönder, 437 00:36:57,220 --> 00:36:59,710 Du kan bara säga, "Åh, rad 6. Jag vet inte vad som händer, 438 00:36:59,710 --> 00:37:03,670 men något om ledningen 6 orsakar mitt program för att bryta. " 439 00:37:03,670 --> 00:37:10,430 Det andra sättet att göra det är att du kan använda detta kommando kallas lista i GDB. 440 00:37:10,430 --> 00:37:13,650 Du kan också förkorta den med l. 441 00:37:13,650 --> 00:37:18,910 Så om vi slår jag, vad vi hit? 442 00:37:18,910 --> 00:37:21,160 Vi får en massa konstiga saker. 443 00:37:21,160 --> 00:37:26,030 Detta är den verkliga assemblerkod 444 00:37:26,030 --> 00:37:29,860 som är i strcmp_sse4_2. 445 00:37:29,860 --> 00:37:32,440 Detta ser typ av funky, 446 00:37:32,440 --> 00:37:36,520 och anledningen vi får detta beror just nu, 447 00:37:36,520 --> 00:37:40,160 GDB har oss i ram 0. 448 00:37:40,160 --> 00:37:43,070 >> Så fort vi ser på variabler, varje gång vi tittar på källkoden, 449 00:37:43,070 --> 00:37:50,530 vi tittar på källkoden som hänför sig till stacken ram vi nu i. 450 00:37:50,530 --> 00:37:53,200 Så för att få något meningsfullt, måste vi 451 00:37:53,200 --> 00:37:57,070 flytta till en skorsten ram som är mer förnuftigt. 452 00:37:57,070 --> 00:38:00,180 I detta fall skulle den största stacken ramen gör lite mer känsla, 453 00:38:00,180 --> 00:38:02,680 eftersom det var faktiskt den kod som vi skrev. 454 00:38:02,680 --> 00:38:05,330 Inte strcmp koden. 455 00:38:05,330 --> 00:38:08,650 Det sätt du kan flytta mellan ramarna, i detta fall, eftersom vi har två, 456 00:38:08,650 --> 00:38:10,430 vi har 0 och 1, 457 00:38:10,430 --> 00:38:13,650 du gör det med upp och ner-kommandon. 458 00:38:13,650 --> 00:38:18,480 Om jag flyttar upp en ram, 459 00:38:18,480 --> 00:38:21,770 nu är jag i huvudsak stacken ram. 460 00:38:21,770 --> 00:38:24,330 Jag kan flytta ner för att gå tillbaka till där jag var, 461 00:38:24,330 --> 00:38:32,830 gå upp igen, gå ner igen, och gå upp igen. 462 00:38:32,830 --> 00:38:39,750 Om du någonsin gör ditt program i GDB får du en krasch, får du bakåtspårning, 463 00:38:39,750 --> 00:38:42,380 och du ser att det är i någon fil som du inte vet vad som händer. 464 00:38:42,380 --> 00:38:45,460 Du försöker lista ser koden inte bekant för dig, 465 00:38:45,460 --> 00:38:48,150 ta en titt på dina bilder och räkna ut var du befinner dig. 466 00:38:48,150 --> 00:38:51,010 Du är förmodligen i fel stacken ram. 467 00:38:51,010 --> 00:38:58,760 Eller åtminstone du är i en skorsten ram som inte är en som du verkligen kan felsöka. 468 00:38:58,760 --> 00:39:03,110 Nu när vi är i rätt stackram, vi är i huvud, 469 00:39:03,110 --> 00:39:08,100 Nu kan vi använda kommandot list att lista ut vad linjen var. 470 00:39:08,100 --> 00:39:13,590 Och du kan se det, det skrivs det för oss här. 471 00:39:13,590 --> 00:39:19,470 Men vi kan slå lista alla lika, och listan ger oss denna fina utskrift 472 00:39:19,470 --> 00:39:23,920 av den faktiska källkod som händer här. 473 00:39:23,920 --> 00:39:26,420 >> I synnerhet, kan vi titta på ledningen 6. 474 00:39:26,420 --> 00:39:29,330 Vi kan se vad som händer här. 475 00:39:29,330 --> 00:39:31,250 Och det ser ut som vi gör en sträng jämförelse 476 00:39:31,250 --> 00:39:41,050 mellan strängen "CS50 rocks" och argv [1]. 477 00:39:41,050 --> 00:39:45,700 Något om detta krascha. 478 00:39:45,700 --> 00:39:54,120 Så Missy, har du några tankar om vad som kan händer här? 479 00:39:54,120 --> 00:39:59,400 [Missy] Jag vet inte varför det är kraschar. >> Du vet inte varför det är kraschar? 480 00:39:59,400 --> 00:40:02,700 Jimmy, några tankar? 481 00:40:02,700 --> 00:40:06,240 [Jimmy] Jag är inte helt säker, men förra gången vi använde sträng jämföra, 482 00:40:06,240 --> 00:40:10,260 eller strcmp hade vi som tre olika fall under den. 483 00:40:10,260 --> 00:40:12,800 Vi hade inte en ==, tror jag inte, mitt i den första raden. 484 00:40:12,800 --> 00:40:16,700 Istället separerades i tre, och en var == 0, 485 00:40:16,700 --> 00:40:19,910 en var <0, tror jag, och en var> 0. 486 00:40:19,910 --> 00:40:22,590 Så kanske något sådant? >> Ja. Så det finns denna fråga 487 00:40:22,590 --> 00:40:27,200 av gör vi jämförelsen korrekt? 488 00:40:27,200 --> 00:40:31,660 Stella? Några tankar? 489 00:40:31,660 --> 00:40:38,110 [Stella] Jag är inte säker. >> Osäker. Daniel? Tankar? Okej. 490 00:40:38,110 --> 00:40:44,770 Det visar sig vad som händer här är när vi körde programmet 491 00:40:44,770 --> 00:40:48,370 och vi fick seg fel, när du körde programmet för första gången, Daniel, 492 00:40:48,370 --> 00:40:50,800 gav du det någon kommandoradsargument? 493 00:40:50,800 --> 00:40:58,420 [Daniel] Nej >> Nej I så fall, vad är värdet av argv [1]? 494 00:40:58,420 --> 00:41:00,920 >> Det finns inget värde. >> Höger. 495 00:41:00,920 --> 00:41:06,120 Tja, det finns inget rätt sträng värde. 496 00:41:06,120 --> 00:41:10,780 Men det finns något värde. Vad är det värde som får lagras där? 497 00:41:10,780 --> 00:41:15,130 >> En sopor värde? >> Det är antingen ett skräp värde eller, i detta fall, 498 00:41:15,130 --> 00:41:19,930 änden av argv matrisen alltid avslutas med null. 499 00:41:19,930 --> 00:41:26,050 Så vad som egentligen blev lagrats i det är null. 500 00:41:26,050 --> 00:41:30,810 Det andra sättet att lösa detta, snarare än att tänka igenom det, 501 00:41:30,810 --> 00:41:33,420 är att försöka skriva ut. 502 00:41:33,420 --> 00:41:35,880 Det är där jag sa att använda GDB är stor, 503 00:41:35,880 --> 00:41:40,640 eftersom du kan skriva ut alla variabler, alla värden som du vill 504 00:41:40,640 --> 00:41:43,230 använda denna behändiga-dandy p kommandot. 505 00:41:43,230 --> 00:41:48,520 Så om jag skriver p och då jag skriver värdet på en variabel eller namnet på en variabel, 506 00:41:48,520 --> 00:41:55,320 säga argc ser jag att argc är 1. 507 00:41:55,320 --> 00:42:01,830 Om jag vill skriva ut argv [0], kan jag göra det bara så där. 508 00:42:01,830 --> 00:42:04,840 Och som vi såg, argv [0] är alltid namnet på ditt program, 509 00:42:04,840 --> 00:42:06,910 alltid namnet på den körbara. 510 00:42:06,910 --> 00:42:09,740 Här ser det har fått den fullständiga sökvägen. 511 00:42:09,740 --> 00:42:15,920 Jag kan också skriva ut argv [1] och se vad som händer. 512 00:42:15,920 --> 00:42:20,890 >> Här fick vi den här typen av mystiska värde. 513 00:42:20,890 --> 00:42:23,890 Vi fick denna 0x0. 514 00:42:23,890 --> 00:42:27,850 Tänk i början av perioden när vi pratade om hexadecimala tal? 515 00:42:27,850 --> 00:42:34,680 Eller den lilla frågan i slutet av pset 0 om hur man representera 50 i hex! 516 00:42:34,680 --> 00:42:39,410 Det sätt vi skriver hexadecimala tal i CS, bara inte förvirra oss 517 00:42:39,410 --> 00:42:46,080 med decimaltal, är vi alltid prefix dem 0x. 518 00:42:46,080 --> 00:42:51,420 Så denna prefixet 0x alltid bara betyder tolka följande nummer som ett hexadecimalt tal, 519 00:42:51,420 --> 00:42:57,400 inte som en sträng, inte som ett decimaltal, inte som ett binärt tal. 520 00:42:57,400 --> 00:43:02,820 Eftersom antalet 5-0 är ett giltigt nummer i hexadecimal. 521 00:43:02,820 --> 00:43:06,240 Och det är ett nummer i decimal, 50. 522 00:43:06,240 --> 00:43:10,050 Så detta är bara hur vi disambiguera. 523 00:43:10,050 --> 00:43:14,860 Så 0x0 betyder hexadecimalt 0, vilket också decimal 0, binära 0. 524 00:43:14,860 --> 00:43:17,030 Det är bara värdet 0. 525 00:43:17,030 --> 00:43:22,630 Det visar sig att detta är vad null är, faktiskt, i minnet. 526 00:43:22,630 --> 00:43:25,940 Null är bara 0. 527 00:43:25,940 --> 00:43:37,010 Här, elementet lagrades vid argv [1] är null. 528 00:43:37,010 --> 00:43:45,220 Så vi försöker jämföra vår "CS50 rocks" sträng till en tom sträng. 529 00:43:45,220 --> 00:43:48,130 Så dereferencing null, försöker komma åt saker på noll, 530 00:43:48,130 --> 00:43:55,050 de är oftast kommer att orsaka någon form av segmentering fel eller andra dåliga saker att hända. 531 00:43:55,050 --> 00:43:59,350 Och det visar sig att strcmp inte kontrollera 532 00:43:59,350 --> 00:44:04,340 om du har passerat i ett värde som är noll. 533 00:44:04,340 --> 00:44:06,370 Snarare det bara går framåt, försöker göra sin grej, 534 00:44:06,370 --> 00:44:14,640 och om det seg fel, seg det fel, och det är ditt problem. Du måste gå fixa det. 535 00:44:14,640 --> 00:44:19,730 Riktigt snabbt, hur kan vi lösa detta problem? Charlotte? 536 00:44:19,730 --> 00:44:23,540 [Charlotte] Du kan kontrollera med om. 537 00:44:23,540 --> 00:44:32,240 Så om argv [1] är null == 0, sedan tillbaka 1, eller något [obegripligt]. 538 00:44:32,240 --> 00:44:34,590 >> Ja. Så det är en bra sätt att göra det, eftersom vi kan kontrollera, 539 00:44:34,590 --> 00:44:39,230 det värde vi är på väg att passera in strcmp, argv [1], är null den? 540 00:44:39,230 --> 00:44:45,830 Om det är noll, då kan vi säga okej, avbryta. 541 00:44:45,830 --> 00:44:49,450 >> Ett vanligare sätt att göra detta är att använda argc värdet. 542 00:44:49,450 --> 00:44:52,040 Du kan se här i början av huvud, 543 00:44:52,040 --> 00:44:58,040 Vi utelämnat som första test som vi vanligtvis gör när vi använder kommandoradsargument, 544 00:44:58,040 --> 00:45:05,240 vilket är att testa huruvida våra argc värde är vad vi förväntar oss. 545 00:45:05,240 --> 00:45:10,290 I det här fallet, vi förväntar åtminstone två argument, 546 00:45:10,290 --> 00:45:13,660 namnet på programmet plus en annan. 547 00:45:13,660 --> 00:45:17,140 Eftersom vi är på väg att använda det andra argumentet här. 548 00:45:17,140 --> 00:45:21,350 Så att ha någon form av test i förväg, innan vår strcmp samtal 549 00:45:21,350 --> 00:45:37,390 att tester eller inte argv är minst 2, skulle också göra samma sak. 550 00:45:37,390 --> 00:45:40,620 Vi kan se om det fungerar genom att köra programmet igen. 551 00:45:40,620 --> 00:45:45,610 Du kan alltid starta om program inom GDB, vilket är riktigt nice. 552 00:45:45,610 --> 00:45:49,310 Du kan köra, och när du passerar på argument till ditt program, 553 00:45:49,310 --> 00:45:53,060 du passerar dem i när du ringer springa, inte när du startar upp GDB. 554 00:45:53,060 --> 00:45:57,120 På så sätt kan du hålla åberopar ditt program med olika argument varje gång. 555 00:45:57,120 --> 00:46:08,080 Så kör, eller igen, kan jag typ R, och låt oss se vad som händer om vi skriver "Hej". 556 00:46:08,080 --> 00:46:11,140 Det kommer alltid att fråga dig om du vill starta det från början igen. 557 00:46:11,140 --> 00:46:17,490 Vanligtvis vill du starta det från början igen. 558 00:46:17,490 --> 00:46:25,010 Och på denna punkt, det startar den igen, skriver ut 559 00:46:25,010 --> 00:46:28,920 det program som vi kör, buggy1, med argumentet hej, 560 00:46:28,920 --> 00:46:32,720 och det skriver denna standard ut, det säger, "Du får ett D," ledsen ansikte. 561 00:46:32,720 --> 00:46:37,610 Men vi inte seg fel. Det sägs att processen avslutades normalt. 562 00:46:37,610 --> 00:46:39,900 Så det ser ganska bra ut. 563 00:46:39,900 --> 00:46:43,050 Inga fler seg fel, vi gjorde det tidigare, 564 00:46:43,050 --> 00:46:48,190 så det ser ut som det var verkligen seg fel bugg som vi fick. 565 00:46:48,190 --> 00:46:51,540 Tyvärr säger det oss att vi får ett D. 566 00:46:51,540 --> 00:46:54,090 >> Vi kan gå tillbaka och titta på koden och se vad som händer där 567 00:46:54,090 --> 00:46:57,980 att räkna ut vad var - varför det säger att vi fick ett D. 568 00:46:57,980 --> 00:47:03,690 Låt oss se, här var det sa printf att du fick ett D. 569 00:47:03,690 --> 00:47:08,540 Om vi ​​skriver lista, som du håller skriva lista, det håller iterera ner genom ditt program, 570 00:47:08,540 --> 00:47:10,940 så det kommer att visa dig de första raderna i ditt program. 571 00:47:10,940 --> 00:47:15,450 Sen ska visa dig de närmaste linjer, och nästa bit och nästa bit. 572 00:47:15,450 --> 00:47:18,240 Och det ska fortsätta att försöka gå ner. 573 00:47:18,240 --> 00:47:21,180 Och nu kommer vi till "radnummer 16 är utom räckhåll." 574 00:47:21,180 --> 00:47:23,940 Eftersom det har endast 15 rader. 575 00:47:23,940 --> 00:47:30,310 Om du kommer till denna punkt och du undrar, "Vad ska jag göra?" Du kan använda hjälpen kommandot. 576 00:47:30,310 --> 00:47:34,340 Använd hjälp och sedan ge den namnet på en kommando. 577 00:47:34,340 --> 00:47:36,460 Och du ser GDB ger oss alla här typen av grejer. 578 00:47:36,460 --> 00:47:43,870 Det säger, "Utan argument listar tio fler linjer efter eller runt tidigare notering. 579 00:47:43,870 --> 00:47:47,920 Lista - listar de tio raderna innan - " 580 00:47:47,920 --> 00:47:52,960 Så låt oss försöka använda listan minus. 581 00:47:52,960 --> 00:47:57,000 Och som listar 10 rader tidigare, du kan leka med listan lite. 582 00:47:57,000 --> 00:48:02,330 Du kan göra listan, lista - Du kan ge ännu lista ett antal, som lista 8, 583 00:48:02,330 --> 00:48:07,500 och det kommer att lista de 10 linjerna runt linje 8. 584 00:48:07,500 --> 00:48:10,290 Och du kan se vad som händer här är att du har en enkel om annat. 585 00:48:10,290 --> 00:48:13,980 Om du skriver in CS50 stenar, skriver ut "Du får ett A." 586 00:48:13,980 --> 00:48:16,530 Annars skriver ut "Du får ett D." 587 00:48:16,530 --> 00:48:23,770 Bummer stad. Okej. Ja? 588 00:48:23,770 --> 00:48:26,730 >> [Daniel] Så när jag försökte göra CS50 stenar utan citattecken, 589 00:48:26,730 --> 00:48:29,290 det står "Du får ett D." 590 00:48:29,290 --> 00:48:32,560 Jag behövde citat för att få det att fungera, varför är det? 591 00:48:32,560 --> 00:48:38,490 >> Ja. Det visar sig att när - det är en annan rolig liten godbit - 592 00:48:38,490 --> 00:48:47,900 När du kör programmet, om vi kör det och vi skriver in CS50 stenar, 593 00:48:47,900 --> 00:48:50,800 precis som Daniel sa att han gjorde det, och du trycker på Retur, 594 00:48:50,800 --> 00:48:52,870 det står fortfarande vi få en D. 595 00:48:52,870 --> 00:48:55,580 Och frågan är, varför är det här? 596 00:48:55,580 --> 00:49:02,120 Och det visar sig att både vår terminal och GDB tolka dessa som två olika argument. 597 00:49:02,120 --> 00:49:04,800 För när det finns en plats, som är underförstådd i 598 00:49:04,800 --> 00:49:08,730 det första argumentet slutade, nästa argumentet är på väg att börja. 599 00:49:08,730 --> 00:49:13,260 Sättet att kombinera dem i två eller ledsen, till ett argument, 600 00:49:13,260 --> 00:49:18,510 är att använda citattecken. 601 00:49:18,510 --> 00:49:29,560 Så nu, om vi sätter det inom citationstecken och köra det igen, får vi ett A. 602 00:49:29,560 --> 00:49:38,780 Så bara för att sammanfatta, inga citat, CS50 och stenar tolkas som två olika argument. 603 00:49:38,780 --> 00:49:45,320 Med citat, det tolkas som ett argument helt och hållet. 604 00:49:45,320 --> 00:49:53,070 >> Vi kan se detta med en brytpunkt. 605 00:49:53,070 --> 00:49:54,920 Hittills har vi kört vårt program, och det varit igång 606 00:49:54,920 --> 00:49:58,230 tills antingen det seg fel eller träffar ett fel 607 00:49:58,230 --> 00:50:05,930 eller tills det har lämnat och allt har varit helt bra. 608 00:50:05,930 --> 00:50:08,360 Detta är inte nödvändigtvis det mest användbara sak, för ibland 609 00:50:08,360 --> 00:50:11,840 du har ett fel i ditt program, men det är inte orsakar ett segmenteringsfel. 610 00:50:11,840 --> 00:50:16,950 Det är inte orsakar ditt program för att stoppa eller nåt sånt. 611 00:50:16,950 --> 00:50:20,730 Det sättet att få GDB att pausa ditt program vid en viss punkt 612 00:50:20,730 --> 00:50:23,260 är att sätta en brytpunkt. 613 00:50:23,260 --> 00:50:26,520 Du kan antingen göra detta genom att ställa en brytpunkt på ett funktionsnamn 614 00:50:26,520 --> 00:50:30,770 eller så kan du sätta en brytpunkt på en viss kodrad. 615 00:50:30,770 --> 00:50:34,450 Jag gillar att ställa brytpunkter på funktionsnamn, eftersom - lätt att komma ihåg, 616 00:50:34,450 --> 00:50:37,700 och om du faktiskt gå in och ändra din källkod upp lite, 617 00:50:37,700 --> 00:50:42,020 då din brytpunkt kommer faktiskt bo på samma ställe i din kod. 618 00:50:42,020 --> 00:50:44,760 Medan om du använder radnummer och radnummer ändras 619 00:50:44,760 --> 00:50:51,740 eftersom du lägger till eller tar bort lite kod, då dina brytpunkter är alla helt skruvas upp. 620 00:50:51,740 --> 00:50:58,590 En av de vanligaste sakerna jag gör är sätta en brytpunkt på den huvudsakliga funktionen. 621 00:50:58,590 --> 00:51:05,300 Ofta jag starta upp GDB, jag typ b viktigaste, tryck Enter, och det kommer att sätta en brytpunkt 622 00:51:05,300 --> 00:51:10,630 på den huvudsakliga funktion som bara säger "pausa programmet så fort du börjar köra," 623 00:51:10,630 --> 00:51:17,960 och på det sättet, när jag kör mitt program med, säg, CS50 stenar som två argument 624 00:51:17,960 --> 00:51:24,830 och trycker Enter, blir det till huvudfunktionen och den stannar precis vid den allra första raden, 625 00:51:24,830 --> 00:51:30,620 precis innan den utvärderar strcmp funktionen. 626 00:51:30,620 --> 00:51:34,940 >> Eftersom jag pausat, nu kan jag börja mucking runt och se vad som händer 627 00:51:34,940 --> 00:51:40,250 med alla de olika variabler som skickas till mitt program. 628 00:51:40,250 --> 00:51:43,670 Här kan jag skriva ut argc och se vad som händer. 629 00:51:43,670 --> 00:51:50,030 Se till att argc är 3, eftersom det har fått 3 olika värden i den. 630 00:51:50,030 --> 00:51:54,060 Det har fått namnet på programmet, den har det första argumentet och det andra argumentet. 631 00:51:54,060 --> 00:52:09,330 Vi kan skriva dem ut genom att titta på argv [0], argv [1], och argv [2]. 632 00:52:09,330 --> 00:52:12,030 Så nu kan du också se varför denna strcmp samtal kommer att misslyckas, 633 00:52:12,030 --> 00:52:21,650 eftersom du ser att det gjorde dela upp CS50 och klipporna i två olika argument. 634 00:52:21,650 --> 00:52:27,250 Vid denna punkt, när du har träffat en brytpunkt, kan du fortsätta att gå igenom ditt program 635 00:52:27,250 --> 00:52:32,920 rad för rad, i motsats till start programmet igen. 636 00:52:32,920 --> 00:52:35,520 Så om du inte vill starta programmet igen och bara fortsätta vidare härifrån, 637 00:52:35,520 --> 00:52:41,970 Du kan använda Fortsätt kommandot och fortsätta att köra programmet till slutet. 638 00:52:41,970 --> 00:52:45,010 Precis som det gjorde här. 639 00:52:45,010 --> 00:52:54,880 Men om jag startar programmet CS50 stenar, träffar det min brytpunkten igen, 640 00:52:54,880 --> 00:52:59,670 och den här gången, om jag inte vill gå hela vägen genom resten av programmet, 641 00:52:59,670 --> 00:53:08,040 Jag kan använda nästa kommando, som jag också förkorta med n. 642 00:53:08,040 --> 00:53:12,960 Och detta kommer gå igenom programmet rad för rad. 643 00:53:12,960 --> 00:53:17,530 Så du kan titta på när saker och ting utför, som variabler förändras, eftersom saker och ting få uppdaterad. 644 00:53:17,530 --> 00:53:21,550 Vilket är ganska trevligt. 645 00:53:21,550 --> 00:53:26,570 Den andra häftiga är snarare än att upprepa samma kommando om och om och om igen, 646 00:53:26,570 --> 00:53:30,670 om du bara trycka Enter - så här ser du att jag inte har skrivit in något - 647 00:53:30,670 --> 00:53:33,780 Om jag bara trycka Enter, kommer det att upprepa föregående kommando, 648 00:53:33,780 --> 00:53:36,900 eller den tidigare GDB kommando som jag satte bara in 649 00:53:36,900 --> 00:53:56,000 Jag kan hålla trycka Enter och det ska hålla stegar genom min kod rad för rad. 650 00:53:56,000 --> 00:53:59,310 Jag skulle vilja uppmuntra er att gå kolla in de andra buggig program också. 651 00:53:59,310 --> 00:54:01,330 Vi har inte tid att gå igenom dem alla i dag i snitt. 652 00:54:01,330 --> 00:54:05,890 Källkoden finns där, så att du kan typ av se vad som händer 653 00:54:05,890 --> 00:54:07,730 bakom kulisserna om du verkligen fastnar, 654 00:54:07,730 --> 00:54:11,940 men åtminstone, bara öva startar upp GDB, 655 00:54:11,940 --> 00:54:13,940 kör programmet tills den går sönder på dig, 656 00:54:13,940 --> 00:54:18,260 få bakåtspårning, räkna ut vilken funktion kraschen var, 657 00:54:18,260 --> 00:54:24,450 vilken linje det var på, skriva ut några variabelvärden, 658 00:54:24,450 --> 00:54:30,140 bara så du får en känsla för det, eftersom det verkligen kommer att hjälpa dig att gå framåt. 659 00:54:30,140 --> 00:54:36,340 Vid denna punkt, kommer vi att sluta av GDB, som du gör med sluta eller bara q.. 660 00:54:36,340 --> 00:54:40,460 Om ditt program är i mitten av fortfarande igång, och det har inte lämnat, 661 00:54:40,460 --> 00:54:43,510 det kommer alltid att be dig, "Är du säker på att du verkligen vill avsluta?" 662 00:54:43,510 --> 00:54:48,770 Du kan bara trycka ja. 663 00:54:48,770 --> 00:54:55,250 >> Nu ska vi titta på nästa problem vi har, vilket är katten programmet. 664 00:54:55,250 --> 00:54:59,880 Om du tittar på kort på omdirigering och rör, ser du att Tommy använder programmet 665 00:54:59,880 --> 00:55:07,540 som skriver i princip samtliga produkter en fil på skärmen. 666 00:55:07,540 --> 00:55:12,660 Så om jag kör katt, är detta faktiskt en inbyggd program till apparaten, 667 00:55:12,660 --> 00:55:16,860 och om du har Mac kan du göra det på din Mac även om du öppnar terminalen. 668 00:55:16,860 --> 00:55:25,630 Och vi - katt, låt oss säga, cp.c och tryck på Retur. 669 00:55:25,630 --> 00:55:29,640 Vad detta gjorde, om vi bläddra upp lite och se var vi körde linjen, 670 00:55:29,640 --> 00:55:40,440 eller där vi körde katten kommandot, det bokstavligen bara skrivas ut innehållet i cp.c till vår skärm. 671 00:55:40,440 --> 00:55:44,140 Vi kan köra den igen och du kan sätta i flera filer samtidigt. 672 00:55:44,140 --> 00:55:49,880 Så du kan göra katten cp.c, och sedan kan vi också sammanfoga den Cat.C filen, 673 00:55:49,880 --> 00:55:53,250 vilket är det program som vi är på väg att skriva, 674 00:55:53,250 --> 00:55:58,140 och det kommer ut båda filerna tillbaka till tillbaka till våra skärmen. 675 00:55:58,140 --> 00:56:05,490 Så om vi bläddra upp lite, ser vi att när vi körde denna katt cp.c, Cat.C, 676 00:56:05,490 --> 00:56:17,110 Först skrivs ut cp filen och under den, tryckt ut den Cat.C filen ända ner hit. 677 00:56:17,110 --> 00:56:19,650 Vi kommer att använda detta för att bara få våra fötter våt. 678 00:56:19,650 --> 00:56:25,930 Leka med enkel utskrift till terminalen, se hur det fungerar. 679 00:56:25,930 --> 00:56:39,170 Om ni öppnar upp med gedit Cat.C, tryck Enter, 680 00:56:39,170 --> 00:56:43,760 Du kan se programmet som vi är på väg att skriva. 681 00:56:43,760 --> 00:56:48,980 Vi har tagit med denna fina panna plattan, så att vi inte behöver lägga tid på att skriva allt ut. 682 00:56:48,980 --> 00:56:52,310 Vi kontrollerar också många argument som skickas in 683 00:56:52,310 --> 00:56:56,910 Vi skriver ut en fin användning meddelande. 684 00:56:56,910 --> 00:57:00,950 >> Detta är det slags saker att igen, som vi har talat om, 685 00:57:00,950 --> 00:57:04,490 det är nästan som muskel minne. 686 00:57:04,490 --> 00:57:07,190 Kom bara ihåg att hålla gör samma sorts saker 687 00:57:07,190 --> 00:57:11,310 och alltid skriva ut någon form av hjälp budskap 688 00:57:11,310 --> 00:57:17,670 så att människor vet hur du kör ditt program. 689 00:57:17,670 --> 00:57:21,630 Med katt, det är ganska enkelt, vi ska bara gå igenom alla de olika argumenten 690 00:57:21,630 --> 00:57:24,300 som skickas till vårt program, och vi kommer att skriva ut 691 00:57:24,300 --> 00:57:29,950 deras innehåll ut till skärmen en i taget. 692 00:57:29,950 --> 00:57:35,670 För att skriva ut filer ut till skärmen, vi kommer att göra något liknande 693 00:57:35,670 --> 00:57:38,120 vad vi gjorde i slutet av testet. 694 00:57:38,120 --> 00:57:45,350 I slutet av testet, som hyr programmet hade vi att öppna upp en fil, 695 00:57:45,350 --> 00:57:48,490 och sedan var vi tvungna att skriva ut på den. 696 00:57:48,490 --> 00:57:54,660 I det här fallet kommer vi att öppna upp en fil, och vi kommer att läsa från den i stället. 697 00:57:54,660 --> 00:58:00,630 Sen ska vi ut, i stället för till en fil kommer vi att skriva på skärmen. 698 00:58:00,630 --> 00:58:05,830 Så utskrift till skärmen du har alla gjort innan med printf. 699 00:58:05,830 --> 00:58:08,290 Så det är inte alltför galen. 700 00:58:08,290 --> 00:58:12,190 Men läser en fil är lite konstigt. 701 00:58:12,190 --> 00:58:17,300 Vi kommer att gå igenom det en liten bit i taget. 702 00:58:17,300 --> 00:58:20,560 Om ni går tillbaka till det sista problemet på frågesport, problemet 33, 703 00:58:20,560 --> 00:58:27,280 den första raden som vi ska göra här, öppna filen, är mycket likt det vi gjorde där. 704 00:58:27,280 --> 00:58:36,370 Så Stella, vad den raden ser ut, när vi öppnar en fil? 705 00:58:36,370 --> 00:58:47,510 [Stella] Capital FIL *, fil - >> Okej. >> - Är lika med fopen. >> Japp. 706 00:58:47,510 --> 00:58:55,980 Som i detta fall är? Det är i kommentaren. 707 00:58:55,980 --> 00:59:06,930 >> Det är i kommentar? argv [i] och r? 708 00:59:06,930 --> 00:59:11,300 >> Exakt. Rätt på. Så Stella är helt rätt. 709 00:59:11,300 --> 00:59:13,720 Detta är vad raden ser ut. 710 00:59:13,720 --> 00:59:19,670 Vi kommer att få en variabel filflödet, förvara den i en fil *, så alla mössor, 711 00:59:19,670 --> 00:59:25,720 FIL, *, och namnet på denna variabel är fil. 712 00:59:25,720 --> 00:59:32,250 Vi kan kalla det vad vi vill. Vi kan kalla det first_file eller file_i, vad vi vill. 713 00:59:32,250 --> 00:59:37,590 Och sedan namnet på filen antogs i på kommandoraden i programmet. 714 00:59:37,590 --> 00:59:44,450 Så det är lagrat i argv [i,] och sedan ska vi öppna filen i skrivskyddat läge. 715 00:59:44,450 --> 00:59:48,100 Nu när vi har öppnat filen är vad det som vi alltid måste komma ihåg att göra 716 00:59:48,100 --> 00:59:52,230 när vi har öppnat en fil? Stänga det. 717 00:59:52,230 --> 00:59:57,220 Så Missy, hur vi stänger en fil? 718 00:59:57,220 --> 01:00:01,020 [Missy] fclose (fil) >> fclose (fil). Exakt. 719 01:00:01,020 --> 01:00:05,340 Jättebra. Okej. Om vi ​​tittar på det här att göra kommentar här, 720 01:00:05,340 --> 01:00:11,940 står det "Open argv [i] och skriv ut dess innehåll till stdout." 721 01:00:11,940 --> 01:00:15,460 >> Standard ut är ett konstigt namn. Stdout är bara vårt sätt att säga 722 01:00:15,460 --> 01:00:22,880 Vi vill skriva ut den till terminalen, vi vill skriva ut det till standard ut strömmen. 723 01:00:22,880 --> 01:00:26,450 Vi kan faktiskt bli av med denna kommentar just här. 724 01:00:26,450 --> 01:00:36,480 Jag ska kopiera den och klistra in den eftersom det är vad vi gjorde. 725 01:00:36,480 --> 01:00:41,290 Vid denna punkt, nu måste vi läsa filen bit för bit. 726 01:00:41,290 --> 01:00:46,300 Vi har diskuterat ett par olika sätt att läsa filer. 727 01:00:46,300 --> 01:00:51,830 Vilka är dina favoriter hittills? 728 01:00:51,830 --> 01:00:57,960 Vilka vägar har ni sett eller minns du, att läsa filer? 729 01:00:57,960 --> 01:01:04,870 [Daniel] fread? >> Fread? Så fread är en. Jimmy, vet du några andra? 730 01:01:04,870 --> 01:01:12,150 [Jimmy] Nej >> Okej. Nix. Charlotte? Alexander? Några andra? Okej. 731 01:01:12,150 --> 01:01:20,740 Så de andra är fgetc är en som vi kommer att använda mycket. 732 01:01:20,740 --> 01:01:26,410 Det finns också fscanf, ni ser ett mönster här? 733 01:01:26,410 --> 01:01:29,170 De börjar alla med f.. Något att göra med en fil. 734 01:01:29,170 --> 01:01:35,260 Det finns fread, fgetc, fscanf. Dessa är alla läser funktioner. 735 01:01:35,260 --> 01:01:49,120 För att skriva att vi har fwrite har vi fputc istället för fgetc. 736 01:01:49,120 --> 01:01:58,250 Vi har även gillar fprintf vi såg på testet. 737 01:01:58,250 --> 01:02:01,680 Eftersom detta är ett problem som innebär att läsa från en fil, 738 01:02:01,680 --> 01:02:04,940 Vi kommer att använda en av dessa tre funktioner. 739 01:02:04,940 --> 01:02:10,890 Vi kommer inte att använda dessa funktioner här nere. 740 01:02:10,890 --> 01:02:14,880 Dessa funktioner är alla finns i standard I / O-bibliotek. 741 01:02:14,880 --> 01:02:17,510 Så om du tittar på toppen av detta program, 742 01:02:17,510 --> 01:02:24,110 kan du se att vi redan har tagit med huvudet filen för standard I / O-bibliotek. 743 01:02:24,110 --> 01:02:27,120 Om vi ​​vill ta reda på vilken vi vill använda, 744 01:02:27,120 --> 01:02:29,690 Vi kan alltid öppna upp man-sidor. 745 01:02:29,690 --> 01:02:34,350 Så vi kan skriva människan stdio 746 01:02:34,350 --> 01:02:43,180 och läs allt om stdio in-och utgångsfunktioner i C. 747 01:02:43,180 --> 01:02:49,870 Och vi kan redan se Åh, titta. Det nämna fgetc, det nämna fputc. 748 01:02:49,870 --> 01:02:57,220 Så du kan borra ner lite och titta på, säg, fgetc 749 01:02:57,220 --> 01:03:00,060 och titta på dess manualsida. 750 01:03:00,060 --> 01:03:03,430 Du kan se att det går tillsammans med en massa andra funktioner: 751 01:03:03,430 --> 01:03:12,640 fgetc, fgets, getc, getchar blir, ungetc och dess inmatning av tecken och strängar. 752 01:03:12,640 --> 01:03:19,180 Så detta är hur vi läser i tecken och strängar från filer från standard input, 753 01:03:19,180 --> 01:03:21,990 som är väsentligen från användaren. 754 01:03:21,990 --> 01:03:24,780 Och det är hur vi gör det i själva C. 755 01:03:24,780 --> 01:03:30,850 Så detta inte använder GetString och getchar funktioner 756 01:03:30,850 --> 01:03:36,840 som vi använde från CS50 biblioteket. 757 01:03:36,840 --> 01:03:39,710 Vi ska göra det här problemet på ett par olika sätt 758 01:03:39,710 --> 01:03:43,430 så att du kan se två olika sätt att göra det. 759 01:03:43,430 --> 01:03:48,490 Både fread funktion som Daniel nämnde och fgetc är bra sätt att göra det. 760 01:03:48,490 --> 01:03:53,790 Jag tror fgetc är lite lättare, eftersom den bara har, som ni ser, 761 01:03:53,790 --> 01:03:59,660 ett argument, filen * som vi försöker läsa karaktär från, 762 01:03:59,660 --> 01:04:02,740 och returvärdet är en int. 763 01:04:02,740 --> 01:04:05,610 Och detta är lite förvirrande, eller hur? 764 01:04:05,610 --> 01:04:11,450 >> Eftersom vi får en karaktär, så varför inte denna avkastning en röding? 765 01:04:11,450 --> 01:04:18,700 Ni har några idéer om varför detta inte kan returnera en char? 766 01:04:18,700 --> 01:04:25,510 [Missy svarar obegripligt] >> yeah. Så Missy är helt rätt. 767 01:04:25,510 --> 01:04:31,570 Om det är ASCII, då detta heltal kan mappas till en faktisk röding. 768 01:04:31,570 --> 01:04:33,520 Kan vara ett ASCII-tecken, och det är rätt. 769 01:04:33,520 --> 01:04:36,220 Det är precis vad som händer. 770 01:04:36,220 --> 01:04:39,190 Vi använder en int helt enkelt eftersom det har fler bitar. 771 01:04:39,190 --> 01:04:44,750 Det är större än en röding, vår tecken endast har 8 bitar, att 1 byte på våra 32-bitars maskiner. 772 01:04:44,750 --> 01:04:48,520 Och en int har alla 4 byte värde av rymden. 773 01:04:48,520 --> 01:04:50,940 Och det visar sig att det sätt fgetc fungerar, 774 01:04:50,940 --> 01:04:53,940 om vi bläddra ner i vår synopsis i man-sidan lite, 775 01:04:53,940 --> 01:05:05,000 rulla hela vägen ner. Det visar sig att de använder denna särskilda värde som kallas EOF. 776 01:05:05,000 --> 01:05:09,640 Det är en speciell konstant som returvärde för fgetc funktion 777 01:05:09,640 --> 01:05:14,570 när du träffar slutet av filen, eller om du får ett felmeddelande. 778 01:05:14,570 --> 01:05:18,170 Och det visar sig att göra dessa jämförelser med EOF korrekt, 779 01:05:18,170 --> 01:05:24,060 du vill ha det där lilla extra mängden information som du har i en int 780 01:05:24,060 --> 01:05:28,420 i motsats till användning av en CHAR-variabel. 781 01:05:28,420 --> 01:05:32,130 Även om fgetc effektivt få en karaktär från en fil, 782 01:05:32,130 --> 01:05:38,450 du vill komma ihåg att det är tillbaka något som är av typen int för dig. 783 01:05:38,450 --> 01:05:41,360 Som sagt, det är ganska lätt att använda. 784 01:05:41,360 --> 01:05:44,960 Det kommer att ge oss ett tecken, så allt vi behöver göra är att fortsätta be filen 785 01:05:44,960 --> 01:05:48,440 "Ge mig nästa tecken, ge mig nästa tecken, ge mig nästa tecken," 786 01:05:48,440 --> 01:05:51,400 tills vi kommer till slutet av filen. 787 01:05:51,400 --> 01:05:54,730 Och det kommer att dra in ett tecken i taget från vår fil, 788 01:05:54,730 --> 01:05:56,250 och då kan vi göra vad vi vill med den. 789 01:05:56,250 --> 01:06:00,160 Vi kan lagra det, kan vi lägga till en sträng, kan vi skriva ut den. 790 01:06:00,160 --> 01:06:04,630 Gör något av detta. 791 01:06:04,630 --> 01:06:09,600 >> Zoomning ut igen och gå tillbaka till vårt Cat.C program, 792 01:06:09,600 --> 01:06:16,170 Om vi ​​ska använda fgetc, 793 01:06:16,170 --> 01:06:21,710 Hur kan vi närma detta nästa kodrad? 794 01:06:21,710 --> 01:06:26,020 Vi kommer att använda - fread kommer att göra något lite annorlunda. 795 01:06:26,020 --> 01:06:32,600 Och den här gången kommer vi bara att använda fgetc att få ett tecken i taget. 796 01:06:32,600 --> 01:06:40,910 Att bearbeta en hel fil, vad kan vi göra? 797 01:06:40,910 --> 01:06:44,030 Hur många tecken är det i en fil? 798 01:06:44,030 --> 01:06:47,390 Det finns en hel del. Så vill du förmodligen att få en 799 01:06:47,390 --> 01:06:49,860 och sedan få en annan och få en annan och få en annan. 800 01:06:49,860 --> 01:06:53,330 Vilken typ av algoritm tror du att vi kanske måste använda här? 801 01:06:53,330 --> 01:06:55,470 Vilken typ av -? [Alexander] en for-loop? >> Exakt. 802 01:06:55,470 --> 01:06:57,500 Någon typ av slinga. 803 01:06:57,500 --> 01:07:03,380 En for-slinga är faktiskt bra, i det här fallet. 804 01:07:03,380 --> 01:07:08,620 Och som du sa, det låter som du vill ha en slinga över hela filen, 805 01:07:08,620 --> 01:07:11,820 få ett tecken åt gången. 806 01:07:11,820 --> 01:07:13,850 Några förslag på vad som kan se ut? 807 01:07:13,850 --> 01:07:22,090 [Alexander, obegripligt] 808 01:07:22,090 --> 01:07:30,050 >> Okej, berätta bara på engelska vad du försöker göra? [Alexander, obegripligt] 809 01:07:30,050 --> 01:07:36,270 Så i det här fallet, det låter som vi försöker bara slinga över hela filen. 810 01:07:36,270 --> 01:07:45,330 [Alexander] Så jag > Storleken på -? 811 01:07:45,330 --> 01:07:49,290 Jag antar att storleken på filen, eller hur? Storleken - we'll skriva precis det så här. 812 01:07:49,290 --> 01:07:57,470 Storlek på filen för närvarande, i + +. 813 01:07:57,470 --> 01:08:04,610 Så det visar sig att det sätt du gör detta med fgetc, och detta är nytt, 814 01:08:04,610 --> 01:08:10,460 är att det finns inget enkelt sätt att bara få storleken på en fil 815 01:08:10,460 --> 01:08:16,979 med denna "sizeof" typ av konstruktion som du har sett förut. 816 01:08:16,979 --> 01:08:20,910 När vi använder det fgetc funktion, vi införa någon form av 817 01:08:20,910 --> 01:08:29,069 nya, funky syntax detta för slinga, där i stället för att använda bara en grundläggande räknare 818 01:08:29,069 --> 01:08:33,920 att gå tecken för tecken, kommer vi att dra ett tecken i taget, 819 01:08:33,920 --> 01:08:37,120 ett tecken i taget, och hur vi vet att vi är i slutet 820 01:08:37,120 --> 01:08:41,290 inte när vi har räknat ett visst antal tecken, 821 01:08:41,290 --> 01:08:49,939 men när karaktären vi drar ut är att särskilda filslut karaktär. 822 01:08:49,939 --> 01:08:58,689 Så vi kan göra detta genom - Jag kallar detta lm, och vi kommer att initiera den 823 01:08:58,689 --> 01:09:08,050 med vår första samtalet för att få det första tecknet från filen. 824 01:09:08,050 --> 01:09:14,979 Så denna del här, detta kommer att få en karaktär ur filen 825 01:09:14,979 --> 01:09:20,840 och lagra det i variabeln lm. 826 01:09:20,840 --> 01:09:25,420 Vi kommer att fortsätta göra detta tills vi kommer till slutet av filen, 827 01:09:25,420 --> 01:09:41,170 vilket vi gör genom att testa för tecken som inte är lika med den där speciella EOF karaktär. 828 01:09:41,170 --> 01:09:48,750 Och sedan istället för att göra ch + +, vilket skulle bara öka värdet, 829 01:09:48,750 --> 01:09:52,710 så om vi läser ett A ur fil, en huvudstad A, säg, 830 01:09:52,710 --> 01:09:56,810 ch + + skulle ge oss b, och vi skulle få c och sedan d.. 831 01:09:56,810 --> 01:09:59,310 Det är uppenbarligen inte vad vi vill. Vad vi vill ha här 832 01:09:59,310 --> 01:10:05,830 i denna sista bit vi vill få nästa tecken från filen. 833 01:10:05,830 --> 01:10:09,500 >> Så hur kan vi få nästa tecken från filen? 834 01:10:09,500 --> 01:10:13,470 Hur får vi det första tecknet från filen? 835 01:10:13,470 --> 01:10:17,200 [Student] fgetfile? >> Fgetc, eller ledsen, du helt rätt. 836 01:10:17,200 --> 01:10:20,470 Jag felstavade det där. Så ja. 837 01:10:20,470 --> 01:10:26,240 Här i stället för att göra ch + +, 838 01:10:26,240 --> 01:10:29,560 Vi ska bara ringa fgetc (fil) igen 839 01:10:29,560 --> 01:10:39,180 och lagra resultatet i vår samma lm variabel. 840 01:10:39,180 --> 01:10:43,730 [Student fråga, obegripligt] 841 01:10:43,730 --> 01:10:52,390 >> Det är där dessa fil * killar är speciell. 842 01:10:52,390 --> 01:10:59,070 Det sätt de arbetar är de - när du öppnar - när du först göra det fopen samtal, 843 01:10:59,070 --> 01:11:04,260 FILE * fungerar effektivt som en pekare till början av filen. 844 01:11:04,260 --> 01:11:12,830 Och sedan varje gång du ringer fgetc, flyttar den en karaktär genom filen. 845 01:11:12,830 --> 01:11:23,280 Så när du kallar detta, du inkrementera filen pekaren ett tecken. 846 01:11:23,280 --> 01:11:26,210 Och när du fgetc igen, du flytta den en annan karaktär 847 01:11:26,210 --> 01:11:28,910 och en annan karaktär och en annan karaktär och ett annat tecken. 848 01:11:28,910 --> 01:11:32,030 [Student fråga, obegripligt] >> Och that - ja. 849 01:11:32,030 --> 01:11:34,810 Det är typ av denna magiska under huven. 850 01:11:34,810 --> 01:11:37,930 Du håller bara uppräkning igenom. 851 01:11:37,930 --> 01:11:46,510 Vid det här laget, du kan faktiskt arbeta med ett tecken. 852 01:11:46,510 --> 01:11:52,150 Så hur kan vi skriva ut det här till skärmen, nu? 853 01:11:52,150 --> 01:11:58,340 Vi kan använda samma printf sak som vi använt tidigare. 854 01:11:58,340 --> 01:12:00,330 Att vi har använt hela terminen. 855 01:12:00,330 --> 01:12:05,450 Vi kan kalla printf, 856 01:12:05,450 --> 01:12:21,300 och vi kan passera i tecknet bara sådär. 857 01:12:21,300 --> 01:12:27,430 Ett annat sätt att göra det är snarare än att använda printf och med att göra detta formatsträng, 858 01:12:27,430 --> 01:12:29,490 Vi kan också använda någon av de andra funktionerna. 859 01:12:29,490 --> 01:12:40,090 Vi kan använda fputc, som skriver ett tecken till skärmen, 860 01:12:40,090 --> 01:12:52,580 förutom om vi tittar på fputc - låt mig zooma ut lite. 861 01:12:52,580 --> 01:12:56,430 Vi ser vad som är trevligt är det tar i det tecken som vi läser med hjälp av fgetc, 862 01:12:56,430 --> 01:13:05,100 men då måste vi ge det en ström för att skriva ut på. 863 01:13:05,100 --> 01:13:11,850 Vi kan också använda putchar funktionen, som kommer att sätta direkt till standard ut. 864 01:13:11,850 --> 01:13:16,070 Så det finns en hel del olika alternativ som vi kan använda för utskrift. 865 01:13:16,070 --> 01:13:19,580 De är alla i standard I / O-bibliotek. 866 01:13:19,580 --> 01:13:25,150 När du vill skriva ut - så printf, som standard, kommer att skriva ut den särskilda standarden ut ström, 867 01:13:25,150 --> 01:13:27,910 nämligen att stdout. 868 01:13:27,910 --> 01:13:41,300 Så vi kan bara hänvisa till det som typ av denna magiska värde, stdout här. 869 01:13:41,300 --> 01:13:48,410 Oops. Sätt semikolon utanför. 870 01:13:48,410 --> 01:13:52,790 >> Detta är en mycket ny, funky information här. 871 01:13:52,790 --> 01:13:58,600 Mycket av detta är mycket idiomatiskt, i den meningen att detta är kod 872 01:13:58,600 --> 01:14:05,700 som skrivs på detta sätt bara för att det är ren att läsa, lätt att läsa. 873 01:14:05,700 --> 01:14:11,520 Det finns många olika sätt att göra det, många olika funktioner som du kan använda, 874 01:14:11,520 --> 01:14:14,680 men vi tenderar att bara följa samma mönster om och om igen. 875 01:14:14,680 --> 01:14:20,180 Så bli inte förvånad om du ser koden ut så här kommer upp igen och igen. 876 01:14:20,180 --> 01:14:25,690 Okej. Vid denna punkt måste vi bryta för dagen. 877 01:14:25,690 --> 01:14:31,300 Tack för att du kom. Tack för att titta om du är online. Och vi ses nästa vecka. 878 01:14:31,300 --> 01:14:33,890 [CS50.TV]