1 00:00:00,000 --> 00:00:02,490 [Powered by Google Translate] [CS50 knjižnica] 2 00:00:02,490 --> 00:00:04,220 [Nate Hardison] [Harvard University] 3 00:00:04,220 --> 00:00:07,260 [To je CS50. CS50.TV] 4 00:00:07,260 --> 00:00:11,510 Knjižnica CS50 je koristno orodje, ki smo jih namestili na napravi 5 00:00:11,510 --> 00:00:15,870 da bi bilo lažje za vas, da napišete programe, ki opozorijo uporabniki za vnos. 6 00:00:15,870 --> 00:00:21,670 V tem video bomo potegnite zaveso in pogledati, kaj točno je v CS50 knjižnici. 7 00:00:21,670 --> 00:00:25,520 >> V videu o knjižnicah C, govorimo o tem, kako vključiti # glav datotek 8 00:00:25,520 --> 00:00:27,570 v knjižnici v izvorno kodo, 9 00:00:27,570 --> 00:00:31,150 in potem se povežete z binarno datoteko knjižnice v fazi povezuje 10 00:00:31,150 --> 00:00:33,140 za urejanje procesa. 11 00:00:33,140 --> 00:00:36,440 V glavi datoteke določite vmesnik za knjižnico. 12 00:00:36,440 --> 00:00:41,280 To pomeni, da so podrobnosti vseh virov, ki jih ima knjižnica na voljo za uporabo, 13 00:00:41,280 --> 00:00:45,250 kot funkcijo izjav, konstant in podatkovnih tipov. 14 00:00:45,250 --> 00:00:48,890 Binarni knjižnica datoteka vsebuje izvajanje knjižnici, 15 00:00:48,890 --> 00:00:54,580 ki je sestavljen iz glave knjižnice, datoteke in knjižnice c. datotek izvorne kode. 16 00:00:54,580 --> 00:00:59,820 >> Binarni Knjižnica datoteka ni zelo zanimivo gledati, saj je, no, v binarno. 17 00:00:59,820 --> 00:01:03,300 Torej, vzemimo si na glavi datoteke za knjižnico namesto tega. 18 00:01:03,300 --> 00:01:07,710 V tem primeru, obstaja samo ena datoteka z imenom glave cs50.h. 19 00:01:07,710 --> 00:01:11,040 Mi smo ga namestili v uporabniku vključujejo imenik 20 00:01:11,040 --> 00:01:15,150 skupaj z drugega sistema knjižničnih glavi datoteke. 21 00:01:15,150 --> 00:01:21,530 >> Ena od prvih stvari, ki jih boste opazili, da cs50.h # vključuje header datoteke iz drugih knjižnic - 22 00:01:21,530 --> 00:01:25,670 float, int meje, standard, in standardni lib. 23 00:01:25,670 --> 00:01:28,800 Še enkrat, po načelu ne izumljanju kolesa, 24 00:01:28,800 --> 00:01:33,490 smo zgradili CS0 knjižnico z orodji, da druge predvidene za nas. 25 00:01:33,490 --> 00:01:38,690 >> Naslednja stvar, ki jo boste videli v knjižnici je, da določite novo vrsto imenovano "string". 26 00:01:38,690 --> 00:01:42,330 Ta linija res samo ustvarja alias char za vrsto *, 27 00:01:42,330 --> 00:01:46,000 tako da ne čudežno podelilo novo vrsto niz z atributi 28 00:01:46,000 --> 00:01:49,650 pogosto povezana s niza objektov v drugih jezikih, 29 00:01:49,650 --> 00:01:50,850 kot dolžino. 30 00:01:50,850 --> 00:01:55,180 Razlog, da smo to storili je, da varuje nove programerje od krvavih podrobnosti 31 00:01:55,180 --> 00:01:57,580 kazalcev, dokler ne bodo pripravljeni. 32 00:01:57,580 --> 00:02:00,130 >> Naslednji del glave datoteke je izjava o funkcijah 33 00:02:00,130 --> 00:02:04,410 da CS50 knjižnica zagotavlja skupaj z dokumentacijo. 34 00:02:04,410 --> 00:02:06,940 Bodite pozorni na stopnjo podrobnosti v pripombah tukaj. 35 00:02:06,940 --> 00:02:10,560 To je super pomembno, da ljudje vedo, kako uporabljati te funkcije. 36 00:02:10,560 --> 00:02:19,150 Izjavljamo, ta pa deluje, da uporabnik in vračanja znakov, dvojice, plovci ints, 37 00:02:19,150 --> 00:02:24,160 dolgo hrepeni, in godala uporabo lastnega niza tip. 38 00:02:24,160 --> 00:02:26,260 V skladu z načelom skrivanje informacij, 39 00:02:26,260 --> 00:02:31,640 smo dal našo definicijo v ločen izvedbeni spisu. C - cs50.c-- 40 00:02:31,640 --> 00:02:35,110 ki se nahaja v imeniku uporabniškega vira. 41 00:02:35,110 --> 00:02:38,040 Pripravili smo to datoteko, tako da si lahko ogledate na to, 42 00:02:38,040 --> 00:02:41,490 iz nje naučili, in jih prevesti na različnih strojih, če želite, 43 00:02:41,490 --> 00:02:45,510 čeprav menimo, da je bolje, da delajo na napravo za ta razred. 44 00:02:45,510 --> 00:02:47,580 Kakorkoli že, pa si oglejte v tem. 45 00:02:49,020 --> 00:02:54,620 >> Naloge GetChar, GetDouble, GetFloat, GetInt, in GetLongLong 46 00:02:54,620 --> 00:02:58,160 Vsi so zgrajene na vrhu GetString funkcije. 47 00:02:58,160 --> 00:03:01,510 Izkazalo se je, da vsi sledijo v bistvu isti vzorec. 48 00:03:01,510 --> 00:03:04,870 Uporabljajo while zanko, da uporabnik za eno vrstico vhoda. 49 00:03:04,870 --> 00:03:08,430 Vrnejo posebno vrednost, če uporabnik vhodi prazno vrstico. 50 00:03:08,430 --> 00:03:11,750 So poskušali razčleniti uporabnika prispevek kot ustreznega tipa, 51 00:03:11,750 --> 00:03:15,010 bilo char, dvojni, float, itd 52 00:03:15,010 --> 00:03:18,710 In potem se bodisi vrnejo rezultat, če je bil vstopni uspešno razčleniti 53 00:03:18,710 --> 00:03:21,330 ali pa reprompt uporabnika. 54 00:03:21,330 --> 00:03:24,230 >> Na visoki ravni, ni nič zapleteno tukaj. 55 00:03:24,230 --> 00:03:28,760 Morda ste napisal podobno strukturiranih kodo se v preteklosti. 56 00:03:28,760 --> 00:03:34,720 Morda je najbolj skrivnosten usmerjen del je sscanf klic, ki razčleni uporabnika prispevek. 57 00:03:34,720 --> 00:03:38,160 Sscanf je del družine format vhodnega konverzije. 58 00:03:38,160 --> 00:03:42,300 Živi v io.h standarda, njegova naloga je, da razčleniti niz C, 59 00:03:42,300 --> 00:03:46,520 v skladu z določeno obliko, skladiščenje razčlembi rezultate spremenljivka 60 00:03:46,520 --> 00:03:48,720 ki jih klicatelja. 61 00:03:48,720 --> 00:03:53,570 Ker so vhodne funkcije za konverzijo formata, so zelo koristne, pogosto uporabljenih funkcij 62 00:03:53,570 --> 00:03:56,160 ki niso zelo intuitiven na prvi, 63 00:03:56,160 --> 00:03:58,300 bomo ogledali, kako sscanf deluje. 64 00:03:58,300 --> 00:04:03,330 >> Prvi argument je sscanf char * - kazalec na znak. 65 00:04:03,330 --> 00:04:05,150 Za funkcija deluje pravilno, 66 00:04:05,150 --> 00:04:08,340 da znak mora biti prvi znak niza C, 67 00:04:08,340 --> 00:04:12,270 zaključi z ničelno \ 0 značaja. 68 00:04:12,270 --> 00:04:15,120 To je niz razčleniti 69 00:04:15,120 --> 00:04:18,269 Drugi argument, da je sscanf formatni niz 70 00:04:18,269 --> 00:04:20,839 običajno sprejet kot konstanten, 71 00:04:20,839 --> 00:04:24,040 in morda boste opazili niz, kot je ta pred uporabo printf. 72 00:04:24,040 --> 00:04:28,650 Znak za odstotek v obliki niza nakazuje določilo pretvorbe. 73 00:04:28,650 --> 00:04:30,850 Znak takoj po znak za odstotek, 74 00:04:30,850 --> 00:04:35,430 označuje tip C, da želimo sscanf pretvoriti. 75 00:04:35,430 --> 00:04:40,090 V GetInt, boste videli, da je% d in% d. 76 00:04:40,090 --> 00:04:48,690 To pomeni, da bo sscanf poskusite decimalno notr - je% d - in char - za% c. 77 00:04:48,690 --> 00:04:51,510 Za vsako določilo pretvorbe v obliki niza, 78 00:04:51,510 --> 00:04:56,620 sscanf pričakuje ustrezno utemeljitev kasneje v spisek argumentov. 79 00:04:56,620 --> 00:05:00,850 To trditev je treba opozoriti, da ustrezno tipkano mesto 80 00:05:00,850 --> 00:05:04,000 v kateri hrani rezultat pretvorbe. 81 00:05:04,000 --> 00:05:08,910 >> Tipičen način za to je, da ustvarite spremenljivko na stack pred klicem sscanf 82 00:05:08,910 --> 00:05:11,440 Za vsak element, ki ga želite razčleniti iz niza 83 00:05:11,440 --> 00:05:15,520 in nato uporabite naslov operaterja - Ta znak -, da prenese kazalcev 84 00:05:15,520 --> 00:05:19,100 teh spremenljivk na razpisu sscanf. 85 00:05:19,100 --> 00:05:22,720 Vidite lahko, da je v GetInt delamo točno to. 86 00:05:22,720 --> 00:05:28,240 Tik pred klicem sscanf izjavljamo, int n imenom in char klicev C na kupu, 87 00:05:28,240 --> 00:05:32,340 in se peljemo navodila o njih v razpisu sscanf. 88 00:05:32,340 --> 00:05:35,800 Prenos teh spremenljivk na stack je prednost pred uporabo dodeljenih prostora 89 00:05:35,800 --> 00:05:39,350 na kup z knjižnične funkcije malloc, ker ste se izognili dodatni obremenitvi na malloc razpisa, 90 00:05:39,350 --> 00:05:43,060 in vam ni treba skrbeti za uhajanje pomnilnika. 91 00:05:43,060 --> 00:05:47,280 Znaki niso predpono znak za odstotek ne pozove konverzijo. 92 00:05:47,280 --> 00:05:50,380 Namesto tega preprosto dodate v formatu specifikacijo. 93 00:05:50,380 --> 00:05:56,500 >> Na primer, če je format niz v GetInt bilo% d namesto tega 94 00:05:56,500 --> 00:05:59,800 sscanf bi si za črko a sledi notr, 95 00:05:59,800 --> 00:06:04,360 in medtem ko bi poskušal spremeniti int, da ne bi naredil ničesar drugega z A. 96 00:06:04,360 --> 00:06:07,440 Edina izjema pri tem je presledek. 97 00:06:07,440 --> 00:06:11,030 Bele presledke v obliki niza ujemata vsak znesek prostorom - 98 00:06:11,030 --> 00:06:12,890 celo sploh ne. 99 00:06:12,890 --> 00:06:18,100 Torej, to je, zakaj je komentar omenja možnosti z vodilnimi in / ali pike, presledke. 100 00:06:18,100 --> 00:06:22,910 Torej, v tem trenutku izgleda, naš poziv sscanf poskusite razčleniti uporabnikov vhodni niz 101 00:06:22,910 --> 00:06:25,380 s preverjanjem za morebitne vodilnih presledkov, 102 00:06:25,380 --> 00:06:29,300 sledi notr, da se bo spreobrnilo in shrani v int spremenljivko n 103 00:06:29,300 --> 00:06:33,090 sledilo nekaj višini presledki, in sledi znak 104 00:06:33,090 --> 00:06:35,810 shranjeni v char spremenljivko c. 105 00:06:35,810 --> 00:06:37,790 >> Kaj vrnjene vrednosti? 106 00:06:37,790 --> 00:06:41,560 Sscanf bo razčleniti vhodne linije od začetka do konca, 107 00:06:41,560 --> 00:06:44,860 ustavi, ko pride do konca ali če znak v vhodni 108 00:06:44,860 --> 00:06:49,320 se ne ujema z obliko značaj ali če ne more narediti spremembo. 109 00:06:49,320 --> 00:06:52,690 To je vrnjena vrednost se uporablja izpostaviti, ko se je ustavila. 110 00:06:52,690 --> 00:06:55,670 Če se je ustavil, ker je dosegel konec vhodnega niza 111 00:06:55,670 --> 00:07:00,630 Pred kakršnim koli spremembam in pred tem, da se ujemajo del formatu niza, 112 00:07:00,630 --> 00:07:04,840 Nato se vrne posebno stalno EOF. 113 00:07:04,840 --> 00:07:08,200 V nasprotnem primeru vrne število uspešnih konverzij 114 00:07:08,200 --> 00:07:14,380 ki je lahko 0, 1 ali 2, odkar smo prosili za dve konverzije. 115 00:07:14,380 --> 00:07:19,000 V našem primeru želimo zagotoviti, da si ga vnesli v notr pa samo notr. 116 00:07:19,000 --> 00:07:23,370 >> Torej, želimo, da se vrnete sscanf 1. Oglejte si, zakaj? 117 00:07:23,370 --> 00:07:26,850 Če sscanf vrne 0, potem pa so bile narejene nobene pretvorbe, 118 00:07:26,850 --> 00:07:31,690 Tako si tipkal nekaj drugega kot notr na začetku vnosa. 119 00:07:31,690 --> 00:07:37,100 Če sscanf vrne 2, nato pa uporabnik ni pravilno ga vnesite v na začetku vnosa, 120 00:07:37,100 --> 00:07:41,390 vendar so nato vnesli v nekaterih lastnostih niso presledkov kasneje 121 00:07:41,390 --> 00:07:44,940 od% c pretvorba uspelo. 122 00:07:44,940 --> 00:07:49,570 To pa je precej dolgotrajen razlaga za 1 klic funkcije. 123 00:07:49,570 --> 00:07:53,460 Kakorkoli že, če želite več informacij o sscanf in njene brate in sestre, 124 00:07:53,460 --> 00:07:57,130 check out man strani, Google, ali oboje. 125 00:07:57,130 --> 00:07:58,780 Obstaja veliko možnosti formatni niz 126 00:07:58,780 --> 00:08:03,830 in ti lahko prihrani veliko ročnega dela, ko poskušajo razčleniti nize v C. 127 00:08:03,830 --> 00:08:07,180 >> Končni funkcijo v knjižnici, ki si je GetString. 128 00:08:07,180 --> 00:08:10,310 Izkazalo se je, da GetString je zapleteno funkcijo pravilno napisati, 129 00:08:10,310 --> 00:08:14,290 čeprav se zdi, kot nekaj tako preprostega, skupno nalogo. 130 00:08:14,290 --> 00:08:16,170 Zakaj je to tako? 131 00:08:16,170 --> 00:08:21,380 No, pa pomislite, kako bomo za shranjevanje črto, da uporabnik vnese palcev 132 00:08:21,380 --> 00:08:23,880 Ker Niz je zaporedje znakov, 133 00:08:23,880 --> 00:08:26,430 mi bi želeli, da jo shranite v matriko na sklad, 134 00:08:26,430 --> 00:08:31,250 vendar pa bi morali vedeti, kako dolgo zaporedje se bo, ko se bo prijavil. 135 00:08:31,250 --> 00:08:34,030 Prav tako, če želimo, da jo položite na kup, 136 00:08:34,030 --> 00:08:38,090 moramo opraviti, da knjižnične funkcije malloc število bajtov, ki jo želimo rezerve, 137 00:08:38,090 --> 00:08:39,730 ampak to je nemogoče. 138 00:08:39,730 --> 00:08:42,760 Ne vemo, koliko znakov bo uporabnik vnesli v 139 00:08:42,760 --> 00:08:46,590 preden si dejansko ne jih vnašate. 140 00:08:46,590 --> 00:08:50,720 >> Naivna rešitev tega problema je, da samo rezervirajo velik kos prostora, recimo, 141 00:08:50,720 --> 00:08:54,540 Blok 1000 znakov za vnos uporabnika, 142 00:08:54,540 --> 00:08:57,980 ob predpostavki, da si ne bi nikoli vnesite v nizu tako dolgo. 143 00:08:57,980 --> 00:09:00,810 To je slaba ideja iz dveh razlogov. 144 00:09:00,810 --> 00:09:05,280 Prvič, ob predpostavki, da uporabniki običajno ne vnesite v kito tako dolgo, 145 00:09:05,280 --> 00:09:07,610 bi lahko odpadki veliko pomnilnika. 146 00:09:07,610 --> 00:09:10,530 V sodobnih strojev, to ne bi bilo problem, če to 147 00:09:10,530 --> 00:09:13,890 v enem ali dveh osamljenih primerih, 148 00:09:13,890 --> 00:09:17,630 ampak, če jemljete uporabnika prispevek v zanki in skladiščenje za poznejšo uporabo, 149 00:09:17,630 --> 00:09:20,870 lahko hitro sesati tone pomnilnika. 150 00:09:20,870 --> 00:09:24,450 Poleg tega, če program, ki ga pišete, je za manjše računalnika - 151 00:09:24,450 --> 00:09:28,100 naprave, kot so pametni ali kaj drugega z omejenim pomnilnikom - 152 00:09:28,100 --> 00:09:32,060 Ta rešitev bo povzročilo težave veliko hitreje. 153 00:09:32,060 --> 00:09:36,450 Druga, bolj tehten razlog za to je, ne da zapusti svoj program ranljive 154 00:09:36,450 --> 00:09:39,710 s tem, kar se imenuje buffer overflow napad. 155 00:09:39,710 --> 00:09:45,840 V načrtovanje, varovalni pomnilnik se uporablja za začasno shranjevanje vhodnih in izhodnih podatkov, 156 00:09:45,840 --> 00:09:48,980 ki v tem primeru je naša 1000-char blok. 157 00:09:48,980 --> 00:09:53,370 Buffer overflow zgodi, ko se podatki pisni mimo konca bloka. 158 00:09:53,370 --> 00:09:57,790 >> Na primer, če si v resnici počne vrsto pri več kot 1000 znakov. 159 00:09:57,790 --> 00:10:01,570 Morda ste doživeli to nesreči pri programiranju z nizi. 160 00:10:01,570 --> 00:10:05,620 Če imate niz 10 ints, da te nič ne ustavi, da bi poskusila brati ali pisati 161 00:10:05,620 --> 00:10:07,810 15. int. 162 00:10:07,810 --> 00:10:10,000 Ni prevajalnika, opozoril ali napak. 163 00:10:10,000 --> 00:10:13,250 Program le blunders naravnost in dostopi spomin 164 00:10:13,250 --> 00:10:18,150 če misli, da bo 15. int, in to lahko prepiše vaše druge spremenljivke. 165 00:10:18,150 --> 00:10:22,040 V najslabšem primeru lahko prepišete nekatere notranje vašega programa 166 00:10:22,040 --> 00:10:26,820 nadzorne mehanizme, zaradi česar vaš program za dejansko izvedbo različnih navodil 167 00:10:26,820 --> 00:10:28,340 kot ste želeli. 168 00:10:28,340 --> 00:10:31,360 >> No, to ni skupna, da to stori po naključju, 169 00:10:31,360 --> 00:10:35,150 ampak to je precej običajna praksa, da slabi ljudje uporabljajo za prekinitev programov 170 00:10:35,150 --> 00:10:39,080 in dal zlonamerne kode na računalnikov drugih ljudi. 171 00:10:39,080 --> 00:10:42,910 Zato se ne moremo preprosto uporabite našo naivno rešitev. 172 00:10:42,910 --> 00:10:45,590 Potrebujemo način za preprečevanje naše programe od tega, da občutljive 173 00:10:45,590 --> 00:10:47,880 na napad buffer overflow. 174 00:10:47,880 --> 00:10:51,430 Če želite to narediti, se moramo prepričati, da lahko naše varovalni rastejo kot beremo 175 00:10:51,430 --> 00:10:53,850 več vnos od uporabnika. 176 00:10:53,850 --> 00:10:57,440 Rešitev? Mi uporabljamo varovalo kopice dodeljena. 177 00:10:57,440 --> 00:10:59,950 Ker lahko velikost jo s Resize realloc funkcijo, 178 00:10:59,950 --> 00:11:04,580 in smo spremljali dve števili - indeks naslednjo prazno režo v varovalnem 179 00:11:04,580 --> 00:11:08,390 in dolžino ali zmogljivost pomnilnika. 180 00:11:08,390 --> 00:11:13,210 Beremo v številu znakov od uporabnika 1 hkrati z uporabo fgetc funkcijo. 181 00:11:13,210 --> 00:11:19,360 The trditvijo fgetc funkcija traja - stdin - je sklicevanje na standardni niz vnosa, 182 00:11:19,360 --> 00:11:23,810 ki je preconnected vhod kanal, ki se uporablja za prenos uporabnika prispevek 183 00:11:23,810 --> 00:11:26,270 iz terminala v program. 184 00:11:26,270 --> 00:11:29,890 >> Kadarkoli uporabnik vnese v nov lik, preverimo, če je indeks 185 00:11:29,890 --> 00:11:35,810 v naslednjem prosti reži plus 1 je večja od zmogljivosti pomnilnika. 186 00:11:35,810 --> 00:11:39,690 Presega 1 prihaja, ker če je naslednji prosti indeks 5, 187 00:11:39,690 --> 00:11:44,150 potem je naše medpomnilnik dolžina 6 zahvaljujoč 0 indeksiranje. 188 00:11:44,150 --> 00:11:48,350 Če smo zmanjka prostora v varovalnem, nato pa bomo poskušali njegovo velikost, 189 00:11:48,350 --> 00:11:51,690 je podvojilo, tako da smo zmanjšali število krat, da velikost 190 00:11:51,690 --> 00:11:54,760 če uporabnik tipka v zelo dolgo vrvico. 191 00:11:54,760 --> 00:11:57,950 Če je niz dobila predolga ali če zmanjka pomnilnika kopice, 192 00:11:57,950 --> 00:12:01,350 smo osvoboditi našo pufer in povratni null. 193 00:12:01,350 --> 00:12:04,170 >> Končno smo dodajte char v pufru. 194 00:12:04,170 --> 00:12:08,200 Ko bo uporabnik vnese ali vrniti, signalizacijski novo vrstico, 195 00:12:08,200 --> 00:12:12,050 ali poseben znak - nadzor d - ki signalizira konec vnosa, 196 00:12:12,050 --> 00:12:16,240 naredimo pregled, da vidim, če je uporabnik dejansko vnesli v karkoli. 197 00:12:16,240 --> 00:12:18,820 Če ne, se vrnemo null. 198 00:12:18,820 --> 00:12:22,280 V nasprotnem primeru, saj je naš varovalni je verjetno večji, kot smo potrebovali, 199 00:12:22,280 --> 00:12:24,830 V najslabšem primeru je skoraj dvakrat večji, kot smo potrebovali 200 00:12:24,830 --> 00:12:27,830 saj smo dvakrat vsakič, ko spremenite velikost, 201 00:12:27,830 --> 00:12:31,840 naredimo novo kopijo niza s samo količino prostora, ki ga potrebujemo. 202 00:12:31,840 --> 00:12:34,220 Mi dodamo dodatno 1 do malloc klicu, 203 00:12:34,220 --> 00:12:37,810 tako da je prostor zaradi posebnega značaja null terminatorja - za \ 0, 204 00:12:37,810 --> 00:12:41,990 ki smo jih dodajte v nizu, ko smo kopirali v ostalih likov, 205 00:12:41,990 --> 00:12:45,060 z strncpy namesto strcpy 206 00:12:45,060 --> 00:12:48,830 tako da določite, koliko znakov želimo kopirati. 207 00:12:48,830 --> 00:12:51,690 Strcpy kopije, dokler ne zadene \ 0. 208 00:12:51,690 --> 00:12:55,740 Potem smo osvoboditi našo spomin in vrne izvod klicatelja. 209 00:12:55,740 --> 00:12:59,840 >> Kdo je vedel tako enostaven navidezno funkcija se lahko tako zapletena? 210 00:12:59,840 --> 00:13:02,820 Zdaj veš, kaj se dogaja v CS50 knjižnici. 211 00:13:02,820 --> 00:13:06,470 >> Moje ime je Nate Hardison, in to je CS50. 212 00:13:06,470 --> 00:13:08,350 [CS50.TV]