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] [Sveučilište Harvard] 3 00:00:04,220 --> 00:00:07,260 [Ovo je CS50. CS50.TV] 4 00:00:07,260 --> 00:00:11,510 The CS50 knjižnica je koristan alat koji smo instalirali na aparatu 5 00:00:11,510 --> 00:00:15,870 kako bi ga lakše za vas da pisati programe koji redak korisnicima za ulaz. 6 00:00:15,870 --> 00:00:21,670 U ovom video, mi ćemo povući zastor i pogledati što je točno u CS50 knjižnici. 7 00:00:21,670 --> 00:00:25,520 >> U videu o C knjižnicama, govorimo o tome kako se # include zaglavlja datoteka 8 00:00:25,520 --> 00:00:27,570 od knjižnice u svoj izvorni kod, 9 00:00:27,570 --> 00:00:31,150 i onda povezati s binarnim knjižnica datoteku tijekom povezivanja fazi 10 00:00:31,150 --> 00:00:33,140 od kompilacijski procesa. 11 00:00:33,140 --> 00:00:36,440 Datoteke zaglavlja odrediti sučelje knjižnice. 12 00:00:36,440 --> 00:00:41,280 To jest, oni detaljno sve resurse koje knjižnica ima na raspolaganju za korištenje, 13 00:00:41,280 --> 00:00:45,250 kao funkcija deklaracijama, konstante, i vrstama podataka. 14 00:00:45,250 --> 00:00:48,890 Binarni knjižnica datoteka sadrži provedbu knjižnici, 15 00:00:48,890 --> 00:00:54,580 koji je sastavljen iz knjižnice header datoteka i knjižnice. C izvorni kod datoteke. 16 00:00:54,580 --> 00:00:59,820 >> Binarni knjižnica datoteka nije jako zanimljivo pogledati jer je, dobro, u binarnom. 17 00:00:59,820 --> 00:01:03,300 Dakle, neka je pogledati zaglavlja datoteka za knjižnicu umjesto. 18 00:01:03,300 --> 00:01:07,710 U tom slučaju, postoji samo jedna datoteka zaglavlja zove cs50.h. 19 00:01:07,710 --> 00:01:11,040 Mi smo ga instalirali u korisnika uključuju imenik 20 00:01:11,040 --> 00:01:15,150 zajedno s drugim sustavom knjižnica zaglavlja datoteka. 21 00:01:15,150 --> 00:01:21,530 >> Jedna od prvih stvari koje ćete primijetiti je da cs50.h # uključuje zaglavlje datoteke iz drugih knjižnica - 22 00:01:21,530 --> 00:01:25,670 float, granice, standardni bool, i standardni lib. 23 00:01:25,670 --> 00:01:28,800 Opet, nakon načelo nije Reinventing točak, 24 00:01:28,800 --> 00:01:33,490 smo izgradili CS0 knjižnicu koristeći alate koje druge predviđene za nas. 25 00:01:33,490 --> 00:01:38,690 >> Sljedeća stvar koju ćete vidjeti u knjižnici je da ćemo definirati novu vrstu pod nazivom "string". 26 00:01:38,690 --> 00:01:42,330 Ova linija stvarno samo stvara alias za char * tip, 27 00:01:42,330 --> 00:01:46,000 tako da ne magično prožeti novi string tip s atributima 28 00:01:46,000 --> 00:01:49,650 obično povezana s gudačkim objekata u drugim jezicima, 29 00:01:49,650 --> 00:01:50,850 kao duljine. 30 00:01:50,850 --> 00:01:55,180 Razlog što smo učinili to je štit novih programera iz krvavih pojedinosti 31 00:01:55,180 --> 00:01:57,580 od pokazivača dok oni spremni. 32 00:01:57,580 --> 00:02:00,130 >> Sljedeći dio datoteke zaglavlja je deklaracija funkcije 33 00:02:00,130 --> 00:02:04,410 da CS50 knjižnica pruža zajedno s dokumentacijom. 34 00:02:04,410 --> 00:02:06,940 Obavijest razinu detalja u komentarima ovdje. 35 00:02:06,940 --> 00:02:10,560 To je super važno da ljudi znaju kako koristiti ove funkcije. 36 00:02:10,560 --> 00:02:19,150 Izjavljujemo, pak, djeluje na brz korisnik i povrat znakovi, parovi, lebdi, Ints, 37 00:02:19,150 --> 00:02:24,160 dugo čezne, i gudače, koristeći vlastitu string tip. 38 00:02:24,160 --> 00:02:26,260 Nakon načela informacijskog skrivanja, 39 00:02:26,260 --> 00:02:31,640 mi smo stavili našu definiciju u odvojeni c provedbe datoteku -. cs50.c-- 40 00:02:31,640 --> 00:02:35,110 nalazi u korisničkom direktoriju izvor. 41 00:02:35,110 --> 00:02:38,040 Osigurali smo tu datoteku, tako da možete pogledati na njega, 42 00:02:38,040 --> 00:02:41,490 učiti iz nje, a to rekompiliranje na različitim strojevima, ako želite, 43 00:02:41,490 --> 00:02:45,510 iako mislim da je bolje da rade na aparatu za ovu klasu. 44 00:02:45,510 --> 00:02:47,580 U svakom slučaju, neka je pogledati sada. 45 00:02:49,020 --> 00:02:54,620 >> Funkcije getchar, GetDouble, GetFloat, GetInt, i GetLongLong 46 00:02:54,620 --> 00:02:58,160 su sve sagrađen na vrhu GetString funkcije. 47 00:02:58,160 --> 00:03:01,510 Ispada da su svi oni slijede u suštini isti uzorak. 48 00:03:01,510 --> 00:03:04,870 Oni koriste while petlja za brz korisnik za jedan redak unosa. 49 00:03:04,870 --> 00:03:08,430 Vraćaju posebnu vrijednost ako korisnik ulazi praznu liniju. 50 00:03:08,430 --> 00:03:11,750 Oni pokušavaju analizirati korisnikov ulaz kao odgovarajućeg tipa, 51 00:03:11,750 --> 00:03:15,010 bilo char, double, float, itd. 52 00:03:15,010 --> 00:03:18,710 A onda su ili vratiti rezultat, ako je ulazni uspješno je analizirano 53 00:03:18,710 --> 00:03:21,330 ili oni reprompt korisnika. 54 00:03:21,330 --> 00:03:24,230 >> Na visokoj razini, ne postoji ništa stvarno lukav ovdje. 55 00:03:24,230 --> 00:03:28,760 Možda su pisali na sličan način strukturiran kôd sebe u prošlosti. 56 00:03:28,760 --> 00:03:34,720 Možda najviše zagonetna izgleda dio je sscanf poziv da analizira korisnikov ulaz. 57 00:03:34,720 --> 00:03:38,160 Sscanf je dio pretvorbe ulazne formatu obitelji. 58 00:03:38,160 --> 00:03:42,300 Ona živi u standardnom io.h, a njegov posao je da izdvoji jedan C string, 59 00:03:42,300 --> 00:03:46,520 prema određenom formatu, spremanje izdvoji rezultate u varijablu 60 00:03:46,520 --> 00:03:48,720 osigurava pozivatelja. 61 00:03:48,720 --> 00:03:53,570 Budući da su ulazni format pretvorbe funkcije su vrlo korisni, naširoko koriste funkcije 62 00:03:53,570 --> 00:03:56,160 da nisu super intuitivno na prvi, 63 00:03:56,160 --> 00:03:58,300 ćemo ići preko kako sscanf radi. 64 00:03:58,300 --> 00:04:03,330 >> Prvi argument da sscanf je char * - pointer na karakter. 65 00:04:03,330 --> 00:04:05,150 Za funkciju da rade ispravno, 66 00:04:05,150 --> 00:04:08,340 taj lik bi trebao biti prvi znak u nizu C, 67 00:04:08,340 --> 00:04:12,270 prestaje s nulte \ 0 karaktera. 68 00:04:12,270 --> 00:04:15,120 To je niz analizirati 69 00:04:15,120 --> 00:04:18,269 Drugi argument za sscanf je format string, 70 00:04:18,269 --> 00:04:20,839 obično prošao u kao string konstante, 71 00:04:20,839 --> 00:04:24,040 a možda ste vidjeli niz ovako prije kada koristite printf. 72 00:04:24,040 --> 00:04:28,650 Posto znak u format string označava pretvorbe specifikator. 73 00:04:28,650 --> 00:04:30,850 Lik je odmah nakon znak za postotak, 74 00:04:30,850 --> 00:04:35,430 ukazuje C-tipa koji želimo sscanf pretvoriti. 75 00:04:35,430 --> 00:04:40,090 U GetInt, vidjet ćete da je% d i% c. 76 00:04:40,090 --> 00:04:48,690 To znači da sscanf će pokušati decimalni int -% d - i char - The% c. 77 00:04:48,690 --> 00:04:51,510 Za svaki pretvorbe specifikator u format string, 78 00:04:51,510 --> 00:04:56,620 sscanf očekuje odgovarajući argument kasnije u popis argumenata. 79 00:04:56,620 --> 00:05:00,850 Taj se argument mora ukazati na odgovarajući način upisali lokaciji 80 00:05:00,850 --> 00:05:04,000 u kojem se pohraniti rezultat pretvorbe. 81 00:05:04,000 --> 00:05:08,910 >> Tipičan način za to je stvoriti varijablu na stog prije sscanf poziva 82 00:05:08,910 --> 00:05:11,440 za svaku stavku koju želite analizirati iz niza 83 00:05:11,440 --> 00:05:15,520 , a zatim koristiti adresu operator - znak za struju - proći pokazivače 84 00:05:15,520 --> 00:05:19,100 onim varijablama do sscanf poziva. 85 00:05:19,100 --> 00:05:22,720 Možete vidjeti da je u GetInt radimo upravo to. 86 00:05:22,720 --> 00:05:28,240 Neposredno prije sscanf poziva, mi proglasi int n zove i char poziva C na stog, 87 00:05:28,240 --> 00:05:32,340 i prolazimo upućuje na njih u sscanf poziva. 88 00:05:32,340 --> 00:05:35,800 Stavljanje ove varijable na stog se preferira nad korištenjem prostora predviđenog 89 00:05:35,800 --> 00:05:39,350 na hrpi s malloc, budući da se izbjegne opterećenje od malloc poziva, 90 00:05:39,350 --> 00:05:43,060 a vi ne morate brinuti o curi memorije. 91 00:05:43,060 --> 00:05:47,280 Likovi nisu prefiksom strane posto znaka ne potaknuti pretvorbu. 92 00:05:47,280 --> 00:05:50,380 Umjesto toga oni samo dodati formatu specifikaciji. 93 00:05:50,380 --> 00:05:56,500 >> Na primjer, ako je format string u GetInt su% d umjesto toga, 94 00:05:56,500 --> 00:05:59,800 sscanf će tražiti pismu je potom int, 95 00:05:59,800 --> 00:06:04,360 i dok to će pokušati pretvoriti int, to ne bi ništa drugo od A. 96 00:06:04,360 --> 00:06:07,440 Jedina iznimka je razmak. 97 00:06:07,440 --> 00:06:11,030 Bijeli prostor likovi u format string odgovara bilo koji iznos od whitespace - 98 00:06:11,030 --> 00:06:12,890 čak uopće. 99 00:06:12,890 --> 00:06:18,100 Dakle, to je razlog zašto komentar spominje eventualno s vodećim i / ili prateći praznine. 100 00:06:18,100 --> 00:06:22,910 Dakle, u ovom trenutku to izgleda kao naše sscanf poziv će pokušati analizirati korisnikovo ulaznog niza 101 00:06:22,910 --> 00:06:25,380 provjerom za moguću vodećih razmakom, 102 00:06:25,380 --> 00:06:29,300 Slijedi int koja će biti pretvorena i pohranjen u varijablu int n 103 00:06:29,300 --> 00:06:33,090 slijedi neki iznos razmakom, a nakon čega slijedi lik 104 00:06:33,090 --> 00:06:35,810 pohranjena u char varijable c. 105 00:06:35,810 --> 00:06:37,790 >> Što o povratku vrijednosti? 106 00:06:37,790 --> 00:06:41,560 Sscanf će analizirati liniju ulaznog od početka do kraja, 107 00:06:41,560 --> 00:06:44,860 zaustavljanje kada dođe do kraja ili kad lik na ulazu 108 00:06:44,860 --> 00:06:49,320 ne odgovara lik formata ili kada to ne može napraviti konverziju. 109 00:06:49,320 --> 00:06:52,690 To je povratna vrijednost se koristi za izdvojiti kada je zaustavljen. 110 00:06:52,690 --> 00:06:55,670 Ako je zaustavljen, jer je do kraja ulaznog niza 111 00:06:55,670 --> 00:07:00,630 prije donošenja bilo kakve pretvorbe i prije nego što nije slagala dio format string, 112 00:07:00,630 --> 00:07:04,840 zatim posebna konstanta EOF vraća. 113 00:07:04,840 --> 00:07:08,200 Inače, ona vraća broj uspješnih pretvorbi, 114 00:07:08,200 --> 00:07:14,380 koji može biti 0, 1, ili 2, jer smo tražili dvije konverzije. 115 00:07:14,380 --> 00:07:19,000 U našem slučaju, želimo biti sigurni da je korisnik upisao u int i samo int. 116 00:07:19,000 --> 00:07:23,370 >> Dakle, želimo sscanf vratiti jedan. Pogledajte zašto? 117 00:07:23,370 --> 00:07:26,850 Ako sscanf vratio 0, onda nema obraćenja su, 118 00:07:26,850 --> 00:07:31,690 tako da korisnik unese nešto drugo nego int na početku ulaza. 119 00:07:31,690 --> 00:07:37,100 Ako sscanf vraća 2, tada je korisnik ispravno uspjeli upisati na početku ulaza, 120 00:07:37,100 --> 00:07:41,390 ali su se tada upisali u neki ne-razmak karaktera poslije 121 00:07:41,390 --> 00:07:44,940 od% c pretvorbe uspio. 122 00:07:44,940 --> 00:07:49,570 Wow, to je prilično dugotrajan objašnjenje za jednu funkcija poziva. 123 00:07:49,570 --> 00:07:53,460 U svakom slučaju, ako želite više informacija o sscanf i njegovih braće i sestara, 124 00:07:53,460 --> 00:07:57,130 check out man stranice, Google, ili oboje. 125 00:07:57,130 --> 00:07:58,780 Postoji puno format string mogućnosti, 126 00:07:58,780 --> 00:08:03,830 a to može uštedjeti puno manualnog rada kada pokušavate analizirati konce u C. 127 00:08:03,830 --> 00:08:07,180 >> Konačna funkcija u knjižnici pogledati je GetString. 128 00:08:07,180 --> 00:08:10,310 Ispada da GetString je lukav funkcija pisati ispravno, 129 00:08:10,310 --> 00:08:14,290 iako se čini kao takav jednostavan, zajednički zadatak. 130 00:08:14,290 --> 00:08:16,170 Zašto je to tako? 131 00:08:16,170 --> 00:08:21,380 Pa, neka je razmišljati o tome kako ćemo za pohranu liniju da korisnik upiše u. 132 00:08:21,380 --> 00:08:23,880 Budući da je niz slijed znakova, 133 00:08:23,880 --> 00:08:26,430 mogli bismo ga želite pohraniti u niz na stog, 134 00:08:26,430 --> 00:08:31,250 ali mi bi trebao znati koliko dugo polje će biti kada smo ga proglasiti. 135 00:08:31,250 --> 00:08:34,030 Isto tako, ako želimo da ga stavi na hrpu, 136 00:08:34,030 --> 00:08:38,090 moramo proći da malloc broj bajtova želimo rezerve, 137 00:08:38,090 --> 00:08:39,730 ali to je nemoguće. 138 00:08:39,730 --> 00:08:42,760 Mi nemamo pojma koliko znakova će korisnik upisati u 139 00:08:42,760 --> 00:08:46,590 prije nego što korisnik zapravo ne ih upisati. 140 00:08:46,590 --> 00:08:50,720 >> Naivna rješenje za ovaj problem je da se samo rezervirati veliki komad prostora, recimo, 141 00:08:50,720 --> 00:08:54,540 blok 1000 znakova za korisnika ulaz, 142 00:08:54,540 --> 00:08:57,980 pod pretpostavkom da je korisnik nikada ne bi upišite u nizu koji je dugo. 143 00:08:57,980 --> 00:09:00,810 To je loša ideja zbog dva razloga. 144 00:09:00,810 --> 00:09:05,280 Prvo, pod pretpostavkom da je korisnik obično ne upisati žice koja je dugo, 145 00:09:05,280 --> 00:09:07,610 mogli trošiti puno memorije. 146 00:09:07,610 --> 00:09:10,530 Na modernim strojevima, to ne može biti problem ako ste to učinili 147 00:09:10,530 --> 00:09:13,890 u jednoj ili dvije izoliranim slučajevima, 148 00:09:13,890 --> 00:09:17,630 ali ako uzimate korisnika ulaz u petlji i spremanje za kasniju uporabu, 149 00:09:17,630 --> 00:09:20,870 možete brzo usisati tonu memorije. 150 00:09:20,870 --> 00:09:24,450 Osim toga, ako se program pišete je za manji računalo - 151 00:09:24,450 --> 00:09:28,100 uređaja poput smartphone ili nešto drugo s ograničenom memorije - 152 00:09:28,100 --> 00:09:32,060 ovo rješenje će uzrokovati probleme puno brže. 153 00:09:32,060 --> 00:09:36,450 Druga, ozbiljnija razlog da ne učiniti to je da to ostavlja svoj program ranjiva 154 00:09:36,450 --> 00:09:39,710 na ono što se zove napad buffer overflow. 155 00:09:39,710 --> 00:09:45,840 U programiranju, tampon je memorija se koristi za privremeno spremanje ulaza ili izlaza podataka, 156 00:09:45,840 --> 00:09:48,980 koja je u ovom slučaju naša 1000-char blok. 157 00:09:48,980 --> 00:09:53,370 Buffer overflow nastaje kada se podaci pisani prošlosti kraju bloka. 158 00:09:53,370 --> 00:09:57,790 >> Na primjer, ako korisnik zapravo tip u više od 1000 znakova. 159 00:09:57,790 --> 00:10:01,570 Možda ste to doživjeli slučajno programiranje s polja. 160 00:10:01,570 --> 00:10:05,620 Ako imate niz od 10 Ints, ništa vas ne prestaje s pokušavao čitati ili pisati 161 00:10:05,620 --> 00:10:07,810 15. Int. 162 00:10:07,810 --> 00:10:10,000 Nema prevodilac upozorenja ili pogreške. 163 00:10:10,000 --> 00:10:13,250 Program samo zabluda ravno i pristupi memorije 164 00:10:13,250 --> 00:10:18,150 gdje da misli da je 15. int će biti, a to se može prepisati svoje druge varijable. 165 00:10:18,150 --> 00:10:22,040 U najgorem slučaju, možete prepisati neke od svoga programa unutarnje 166 00:10:22,040 --> 00:10:26,820 kontrolni mehanizmi, uzrokujući svoj program zapravo izvršiti različite upute 167 00:10:26,820 --> 00:10:28,340 nego što ste mislili. 168 00:10:28,340 --> 00:10:31,360 >> Sada, to nije uobičajeno za to slučajno, 169 00:10:31,360 --> 00:10:35,150 ali to je prilično uobičajena tehnika da loši momci koristiti za break programe 170 00:10:35,150 --> 00:10:39,080 i staviti malicioznog koda na tuđim računalima. 171 00:10:39,080 --> 00:10:42,910 Stoga, ne možemo koristiti našu naivnu rješenje. 172 00:10:42,910 --> 00:10:45,590 Moramo način da se spriječi naše programe od toga da bude ranjiva 173 00:10:45,590 --> 00:10:47,880 u napadu tampon preljeva. 174 00:10:47,880 --> 00:10:51,430 Da biste to učinili, moramo biti sigurni da naš tampon može rasti kao što smo pročitali 175 00:10:51,430 --> 00:10:53,850 više ulaz od korisnika. 176 00:10:53,850 --> 00:10:57,440 Rješenje? Mi koristimo tampon hrpa dodijeljen. 177 00:10:57,440 --> 00:10:59,950 Budući da možemo promijeniti veličinu ga pomoću promjenu veličine realloc funkciju, 178 00:10:59,950 --> 00:11:04,580 i mi pratiti dva broja - indeks sljedeći prazni utor u međuspremniku 179 00:11:04,580 --> 00:11:08,390 i duljine ili kapacitet pufera. 180 00:11:08,390 --> 00:11:13,210 Čitamo u znakovi od korisnika jednog u vrijeme pomoću fgetc funkciju. 181 00:11:13,210 --> 00:11:19,360 The argument fgetc funkcija traje - STDIN - je referenca na standardnom ulaznog niza, 182 00:11:19,360 --> 00:11:23,810 koji je preconnected ulazni kanal koji se koristi za prijenos korisnikov ulaz 183 00:11:23,810 --> 00:11:26,270 iz terminala na programu. 184 00:11:26,270 --> 00:11:29,890 >> Kada korisnik upiše u novi lik, možemo provjeriti da li je indeks 185 00:11:29,890 --> 00:11:35,810 od sljedećeg slobodnog utora plus 1 je veći od kapaciteta spremnika. 186 00:11:35,810 --> 00:11:39,690 Oznake +1 dolazi u jer ako sljedeći slobodni indeks 5, 187 00:11:39,690 --> 00:11:44,150 onda naše međupohrane dužina mora biti šest zahvaljujući 0 indeksiranje. 188 00:11:44,150 --> 00:11:48,350 Ako smo ponestane prostora u spremniku, onda ćemo ga pokušati promijeniti veličinu, 189 00:11:48,350 --> 00:11:51,690 ga udvostručenje tako da smo smanjiti broj puta da smo veličinu 190 00:11:51,690 --> 00:11:54,760 ako je korisnik upisivanjem u jako dugom nizu. 191 00:11:54,760 --> 00:11:57,950 Ako string je stečen predugo ili ako mi ponestane hrpa memorije, 192 00:11:57,950 --> 00:12:01,350 smo oslobodili našu tampon i povratak null. 193 00:12:01,350 --> 00:12:04,170 >> Konačno, mi dodati char na tampon. 194 00:12:04,170 --> 00:12:08,200 Nakon pogotka korisnika ući ili vratiti, signalizirajući novu liniju, 195 00:12:08,200 --> 00:12:12,050 ili posebna char - kontrola d - koji signalizira kraj ulaza, 196 00:12:12,050 --> 00:12:16,240 mi ček vidjeti ako korisnik zapravo upisali u bilo uopće. 197 00:12:16,240 --> 00:12:18,820 Ako ne, mi vratiti null. 198 00:12:18,820 --> 00:12:22,280 Inače, jer je naša tampon je vjerojatno veći nego što nam je potrebno, 199 00:12:22,280 --> 00:12:24,830 u najgorem slučaju to je gotovo dvostruko veća trebamo 200 00:12:24,830 --> 00:12:27,830 jer mi dvaput svaki put smo promijenili veličinu, 201 00:12:27,830 --> 00:12:31,840 ćemo napraviti novu kopiju niza pomoću samo količinu prostora da trebamo. 202 00:12:31,840 --> 00:12:34,220 Mi dodati dodatni 1 do malloc poziva, 203 00:12:34,220 --> 00:12:37,810 tako da postoji prostor za posebnu null terminator karaktera - na \ 0, 204 00:12:37,810 --> 00:12:41,990 koje smo dodati na string jednom smo kopirali u ostatku likova, 205 00:12:41,990 --> 00:12:45,060 pomoću strncpy umjesto strcpy 206 00:12:45,060 --> 00:12:48,830 tako da možemo odrediti koliko točno znakovi želimo kopirati. 207 00:12:48,830 --> 00:12:51,690 Strcpy kopira sve dok se ne udari \ 0. 208 00:12:51,690 --> 00:12:55,740 Tada smo oslobodili našu tampon i vratiti primjerak pozivatelju. 209 00:12:55,740 --> 00:12:59,840 >> Tko je znao kao jednostavan izgledom funkcija mogla biti tako komplicirano? 210 00:12:59,840 --> 00:13:02,820 Sad znate što ide u CS50 knjižnici. 211 00:13:02,820 --> 00:13:06,470 >> Moje ime je Nate Hardison, a ovo je CS50. 212 00:13:06,470 --> 00:13:08,350 [CS50.TV]