1 00:00:00,000 --> 00:00:02,490 [Powered by Google Translate] [CS50 Library] 2 00:00:02,490 --> 00:00:04,220 [Нейт Hardison] [Харвардския университет] 3 00:00:04,220 --> 00:00:07,260 [Това е CS50. CS50.TV] 4 00:00:07,260 --> 00:00:11,510 Библиотеката CS50 е полезен инструмент, че имаме инсталиран на уреда 5 00:00:11,510 --> 00:00:15,870 да направи по-лесно да се пишат програми, които подканят потребителите за вход. 6 00:00:15,870 --> 00:00:21,670 В това видео, ние ще дръпнете завесата и да потърсите какво точно е в CS50 библиотека. 7 00:00:21,670 --> 00:00:25,520 >> В видео библиотеки C, ние говорим за начина, по който # включват заглавията файлове 8 00:00:25,520 --> 00:00:27,570 на библиотеката в изходен код, 9 00:00:27,570 --> 00:00:31,150 и след това се свържете с двоичен файл библиотека по време на свързване фаза 10 00:00:31,150 --> 00:00:33,140 процеса на компилация. 11 00:00:33,140 --> 00:00:36,440 Заглавните файлове уточняват интерфейса на библиотеката. 12 00:00:36,440 --> 00:00:41,280 Това означава, че те подробно на всички ресурси, които библиотеката разполага, за да използвате, 13 00:00:41,280 --> 00:00:45,250 като функция декларации, константи, типове данни. 14 00:00:45,250 --> 00:00:48,890 Двоичен файл Библиотеката съдържа изпълнението на библиотеката, 15 00:00:48,890 --> 00:00:54,580 , който е съставен от заглавните файлове на библиотеката и библиотека в изходните файлове код. 16 00:00:54,580 --> 00:00:59,820 >> Двоичен файл библиотеката не е много интересно да гледам тъй като това е добре, в двоичен. 17 00:00:59,820 --> 00:01:03,300 Така че, нека да погледнем в заглавните файлове за библиотеката, вместо. 18 00:01:03,300 --> 00:01:07,710 В този случай, има само един хедър файл, наречен cs50.h. 19 00:01:07,710 --> 00:01:11,040 Сме го инсталирали в инструкцията за директорията 20 00:01:11,040 --> 00:01:15,150 заедно с заглавните файлове на други библиотеки системи. 21 00:01:15,150 --> 00:01:21,530 >> Едно от първите неща, които ще забележите е, че cs50.h # включва хедър файлове от други библиотеки - 22 00:01:21,530 --> 00:01:25,670 поплавък, граници, стандарт BOOL и стандартни Lib. 23 00:01:25,670 --> 00:01:28,800 Отново, следвайки принципа не преоткрива колелото, 24 00:01:28,800 --> 00:01:33,490 сме изградили CS0 колекция с помощта на инструменти, които други, предвидени за нас. 25 00:01:33,490 --> 00:01:38,690 >> Следващото нещо, което ще видите в библиотеката е, че ние определяме един нов вид, наречен "низ". 26 00:01:38,690 --> 00:01:42,330 Тази линия наистина просто създава псевдоним за Чар тип * 27 00:01:42,330 --> 00:01:46,000 така че не магически придават на нов тип низ с атрибути 28 00:01:46,000 --> 00:01:49,650 често се свързва с струнни обекти в други езици, 29 00:01:49,650 --> 00:01:50,850 като дължина. 30 00:01:50,850 --> 00:01:55,180 Причина, ние сме направили това, е да се предпазят нови програмисти от страховити подробности 31 00:01:55,180 --> 00:01:57,580 от указатели, докато те са готови. 32 00:01:57,580 --> 00:02:00,130 >> Следващата част на заглавния файл е декларацията на функциите 33 00:02:00,130 --> 00:02:04,410 CS50 библиотека предоставя заедно с документация. 34 00:02:04,410 --> 00:02:06,940 Обърнете внимание на нивото на детайлност в коментарите тук. 35 00:02:06,940 --> 00:02:10,560 Това е супер важно, така че хората да знаят как да използват тези функции. 36 00:02:10,560 --> 00:02:19,150 Ние заявяваме, от своя страна, функциите да предизвика символа на потребителя и връщане, двойки, плувки, интеджър 37 00:02:19,150 --> 00:02:24,160 дълго копнее, и струнни, използвайки нашата собствена тип низ. 38 00:02:24,160 --> 00:02:26,260 Следвайки принципа на информация се крие, 39 00:02:26,260 --> 00:02:31,640 ние поставяме нашата дефиниция в отделен файл за изпълнение в cs50.c - 40 00:02:31,640 --> 00:02:35,110 се намира в директорията на потребителския източник. 41 00:02:35,110 --> 00:02:38,040 При условие че сме файл, така че можете да вземете един поглед към него, 42 00:02:38,040 --> 00:02:41,490 се поучим от него и да го компилирате на различни машини, ако желаете, 43 00:02:41,490 --> 00:02:45,510 въпреки че ние смятаме, че е по-добре да работят върху уреда за този клас. 44 00:02:45,510 --> 00:02:47,580 Както и да е, нека хвърлим един поглед към него сега. 45 00:02:49,020 --> 00:02:54,620 >> Функциите GetChar, GetDouble, GetFloat, GetInt, и GetLongLong 46 00:02:54,620 --> 00:02:58,160 са построени на върха на GetString функция. 47 00:02:58,160 --> 00:03:01,510 Оказва се, че всички те следват по същество един и същи модел. 48 00:03:01,510 --> 00:03:04,870 Те използват линия, докато да подтикне потребителя за един ред на входа. 49 00:03:04,870 --> 00:03:08,430 Те се връщат със специална стойност, когато потребителят входа празен ред. 50 00:03:08,430 --> 00:03:11,750 Те се опитват да се направи разбор на въвеждане на потребителя като подходящ тип, 51 00:03:11,750 --> 00:03:15,010 Чар, двойни, с плаваща запетая, и др. 52 00:03:15,010 --> 00:03:18,710 И тогава те се връщат резултат, ако входа беше успешно разбор 53 00:03:18,710 --> 00:03:21,330 или reprompt на потребителя. 54 00:03:21,330 --> 00:03:24,230 >> На по-високо ниво, няма нищо наистина труден. 55 00:03:24,230 --> 00:03:28,760 Може да са писали подобно структуриран код себе си в миналото. 56 00:03:28,760 --> 00:03:34,720 Може би най-загадъчен изглеждащи част е sscanf обаждане, че Интерпретира входа на потребителя. 57 00:03:34,720 --> 00:03:38,160 Sscanf е част от семейството на входа формат преобразуване. 58 00:03:38,160 --> 00:03:42,300 Тя живее в io.h стандарт, а нейната задача е да прави разбор на низ C, 59 00:03:42,300 --> 00:03:46,520 в съответствие с определен формат, съхранение на разбора резултати в променлива 60 00:03:46,520 --> 00:03:48,720 предвидени от повикващия. 61 00:03:48,720 --> 00:03:53,570 Тъй като входните функции формат преобразуване са много полезни, широко използвани функции 62 00:03:53,570 --> 00:03:56,160 , които не са супер интуитивен първа 63 00:03:56,160 --> 00:03:58,300 ние ще отидем как sscanf работи. 64 00:03:58,300 --> 00:04:03,330 >> Първият аргумент sscanf е знак * - показалец към символен. 65 00:04:03,330 --> 00:04:05,150 За да работи функцията правилно, 66 00:04:05,150 --> 00:04:08,340 този характер трябва да бъде на първия знак от низ C 67 00:04:08,340 --> 00:04:12,270 прекратява с нулевата \ 0 характер. 68 00:04:12,270 --> 00:04:15,120 Това е низ, да прави разбор 69 00:04:15,120 --> 00:04:18,269 Вторият аргумент sscanf е низ формат, 70 00:04:18,269 --> 00:04:20,839 обикновено премина като низ константа, 71 00:04:20,839 --> 00:04:24,040 и може да са видели низ като преди, когато се използва ФОРМАТ. 72 00:04:24,040 --> 00:04:28,650 Процент знак във формат низ показва означител за преобразуване. 73 00:04:28,650 --> 00:04:30,850 Характер веднага след знак за процент, 74 00:04:30,850 --> 00:04:35,430 показва типа на C, че искаме sscanf да конвертирате. 75 00:04:35,430 --> 00:04:40,090 В GetInt, ще видите, че е налице% D и C%. 76 00:04:40,090 --> 00:04:48,690 Това означава, че sscanf ще се опита да десетична INT -% г и Чар% в. 77 00:04:48,690 --> 00:04:51,510 За всеки означител за преобразуване във формат низ, 78 00:04:51,510 --> 00:04:56,620 sscanf очаква съответния аргумент по-късно в списъкът с аргументите. 79 00:04:56,620 --> 00:05:00,850 Този аргумент трябва да сочи към подходящо въвели място 80 00:05:00,850 --> 00:05:04,000 , в която да се съхранява в резултат на преобразуването. 81 00:05:04,000 --> 00:05:08,910 >> Типичният начин за това е да създадете променлива в стека преди поканата sscanf 82 00:05:08,910 --> 00:05:11,440 за всеки елемент, който искате да се направи разбор на низ 83 00:05:11,440 --> 00:05:15,520 и след това да използвате адреса оператор - амперсанд - да премине указатели 84 00:05:15,520 --> 00:05:19,100 тези променливи в разговора sscanf. 85 00:05:19,100 --> 00:05:22,720 Можете да видите, че в GetInt правим точно това. 86 00:05:22,720 --> 00:05:28,240 Точно преди поканата sscanf, ние заявяваме, вътр нарича н и в знак покана на стека, 87 00:05:28,240 --> 00:05:32,340 и преминаваме указатели към тях в поканата sscanf. 88 00:05:32,340 --> 00:05:35,800 Поставянето на тези променливи в стека е за предпочитане пред отделено място 89 00:05:35,800 --> 00:05:39,350 на купчина с изчистване, тъй като ще избегнете на изчистване разговор, 90 00:05:39,350 --> 00:05:43,060 и не е нужно да се притеснявате за изтичане на памет. 91 00:05:43,060 --> 00:05:47,280 Знаците, които не са предхождани от знак за процент не доведе до конверсия. 92 00:05:47,280 --> 00:05:50,380 Вместо това те просто добавете към спецификацията на формата. 93 00:05:50,380 --> 00:05:56,500 >> Например, ако форматът на низ в GetInt% г вместо това, 94 00:05:56,500 --> 00:05:59,800 sscanf ще изглежда писмо, последвано от едно цяло число, 95 00:05:59,800 --> 00:06:04,360 и докато той ще се опита да конвертирате Int, не би направил нещо друго, с една. 96 00:06:04,360 --> 00:06:07,440 Единственото изключение от това е празно пространство. 97 00:06:07,440 --> 00:06:11,030 Бели символи пространство във формат низ съвпадат всяка сума на празно място - 98 00:06:11,030 --> 00:06:12,890 дори няма изобщо. 99 00:06:12,890 --> 00:06:18,100 Така че, ето защо коментара се посочва, евентуално с водещи и / или в края на интервали. 100 00:06:18,100 --> 00:06:22,910 Така че, в този момент, тя изглежда като нашата sscanf повикване ще се опита да анализира входния низ на потребителя 101 00:06:22,910 --> 00:06:25,380 от проверка за евентуална водеща празно, 102 00:06:25,380 --> 00:06:29,300 последван от вътр, които ще се конвертират и съхраняват в INT променлива N 103 00:06:29,300 --> 00:06:33,090 последвана от някаква сума на празно пространство, и последван от символ 104 00:06:33,090 --> 00:06:35,810 съхраняват в Чар променлива в. 105 00:06:35,810 --> 00:06:37,790 >> Ами върнатата стойност? 106 00:06:37,790 --> 00:06:41,560 Sscanf ще направи разбор на линейния вход от начало до край, 107 00:06:41,560 --> 00:06:44,860 спиране, когато са достигнали до края или когато герой във входа 108 00:06:44,860 --> 00:06:49,320 не съвпада с характер формат или когато не може да се направи конверсия. 109 00:06:49,320 --> 00:06:52,690 Това е връщаната стойност се използва да изредя, когато тя спря. 110 00:06:52,690 --> 00:06:55,670 Ако го спря, тъй като тя стигна до края на входния низ 111 00:06:55,670 --> 00:07:00,630 преди да направи никакви реализации и преди не е съответства на част от формат низ, 112 00:07:00,630 --> 00:07:04,840 тогава специална постоянна EOF се връща. 113 00:07:04,840 --> 00:07:08,200 В противен случай, той се връща на броя на успешните реализации, 114 00:07:08,200 --> 00:07:14,380 която може да бъде 0, 1 или 2, тъй като сме поискали за две реализации. 115 00:07:14,380 --> 00:07:19,000 В нашия случай, ние искаме да се уверим, че потребителският въвели в едно цяло число и само вътр. 116 00:07:19,000 --> 00:07:23,370 >> Така че, ние искаме sscanf да се върне 1. Вижте защо? 117 00:07:23,370 --> 00:07:26,850 Ако sscanf връща 0, тогава никакви реализации са направени, 118 00:07:26,850 --> 00:07:31,690 така че потребителят написали нещо различно от едно цяло число в началото на входа. 119 00:07:31,690 --> 00:07:37,100 Ако sscanf връща две, а след това, че потребителят не правилно да го въведете в в началото на входа, 120 00:07:37,100 --> 00:07:41,390 но след това те написали в някои не-празно характер след това 121 00:07:41,390 --> 00:07:44,940 тъй% в преобразуване успя. 122 00:07:44,940 --> 00:07:49,570 Уау, това е доста дълго обяснение за една функция разговор. 123 00:07:49,570 --> 00:07:53,460 Както и да е, ако искате повече информация за sscanf и неговите братя и сестри, 124 00:07:53,460 --> 00:07:57,130 разгледайте страниците на човек, Google, или и двете. 125 00:07:57,130 --> 00:07:58,780 Има много опции формат низ, 126 00:07:58,780 --> 00:08:03,830 и това може да ви спести много ръчен труд, когато се опитват да се направи разбор конците в C. 127 00:08:03,830 --> 00:08:07,180 >> Крайният функция в библиотеката да погледнете е GetString. 128 00:08:07,180 --> 00:08:10,310 Оказва се, че GetString е сложен функция, за да пишат правилно, 129 00:08:10,310 --> 00:08:14,290 макар и да изглежда като проста, обща задача. 130 00:08:14,290 --> 00:08:16,170 Защо това е така? 131 00:08:16,170 --> 00:08:21,380 Е, нека помислим за това как ги съхраняват линията на потребителя видове инча 132 00:08:21,380 --> 00:08:23,880 Тъй като низ е последователност от символи, 133 00:08:23,880 --> 00:08:26,430 бихме искали да я съхранява в масив в стека, 134 00:08:26,430 --> 00:08:31,250 но ние ще трябва да знам колко дълго масива ще бъде, когато ние го декларира. 135 00:08:31,250 --> 00:08:34,030 По същия начин, ако искаме да го постави на куп, 136 00:08:34,030 --> 00:08:38,090 ние трябва да се премине към изчистване на броя на байтове, искаме да резервирате 137 00:08:38,090 --> 00:08:39,730 но това е невъзможно. 138 00:08:39,730 --> 00:08:42,760 Ние нямаме представа колко символа потребителят ще напишете 139 00:08:42,760 --> 00:08:46,590 преди потребителят действително не ги въвеждате. 140 00:08:46,590 --> 00:08:50,720 >> Наивно решение на този проблем е просто да запази голяма част от пространството, да речем, 141 00:08:50,720 --> 00:08:54,540 блок от 1000 символа за вход на потребителя, 142 00:08:54,540 --> 00:08:57,980 се предполага, че потребителят не би да въведете низ, който дълго. 143 00:08:57,980 --> 00:09:00,810 Това е лоша идея по две причини. 144 00:09:00,810 --> 00:09:05,280 На първо място, като се предполага, че потребителите обикновено не въведете струни толкова дълго, 145 00:09:05,280 --> 00:09:07,610 можете да губи много памет. 146 00:09:07,610 --> 00:09:10,530 На съвременни машини, това не може да бъде проблем, ако направите това 147 00:09:10,530 --> 00:09:13,890 в една или две изолирани случаи, 148 00:09:13,890 --> 00:09:17,630 но ако сте като въвеждане на потребителя в една линия и съхранява за по-нататъшна употреба, 149 00:09:17,630 --> 00:09:20,870 можете бързо да смучат на тон на паметта. 150 00:09:20,870 --> 00:09:24,450 Освен това, ако програмата, която пишете, е за по-малък компютър - 151 00:09:24,450 --> 00:09:28,100 устройство като смартфон или нещо друго с ограничена памет - 152 00:09:28,100 --> 00:09:32,060 това решение ще доведе до проблеми много по-бързо. 153 00:09:32,060 --> 00:09:36,450 Втората, по-сериозна причина да не направите това е, че то оставя вашата програма уязвими 154 00:09:36,450 --> 00:09:39,710 на това, което се нарича атака за препълване на буфера. 155 00:09:39,710 --> 00:09:45,840 Програмиране, буфер памет се използва за временно съхраняване на входящите или изходящите данни, 156 00:09:45,840 --> 00:09:48,980 който в този случай е 1000-Чар блок. 157 00:09:48,980 --> 00:09:53,370 Препълване на буфера се случва, когато данните се записват след края на блока. 158 00:09:53,370 --> 00:09:57,790 >> Например, ако потребителят всъщност прави вид в повече от 1000 символа. 159 00:09:57,790 --> 00:10:01,570 Може да са имали това случайно, когато програмиране с масиви. 160 00:10:01,570 --> 00:10:05,620 Ако имате масив от 10 цели числа, нищо не ви спира да се опитва да чете или пише 161 00:10:05,620 --> 00:10:07,810 15-ти вътр. 162 00:10:07,810 --> 00:10:10,000 Не са открити компилатора предупреждения или грешки. 163 00:10:10,000 --> 00:10:13,250 Програма само гафове напред и достъп до паметта 164 00:10:13,250 --> 00:10:18,150 случаите, когато смята 15-ти Int ще бъде, и това може да се замести други променливи. 165 00:10:18,150 --> 00:10:22,040 В най-лошия случай, може да се замести част от вашата вътрешна програма 166 00:10:22,040 --> 00:10:26,820 механизмите за контрол, което води до вашата програма да изпълнява различни инструкции 167 00:10:26,820 --> 00:10:28,340 отколкото сте възнамерявали. 168 00:10:28,340 --> 00:10:31,360 >> Сега, това не е обичайно да се направи това случайно, 169 00:10:31,360 --> 00:10:35,150 но това е доста често срещано техника, която лошите момчета използват, за да се прекъсне програми 170 00:10:35,150 --> 00:10:39,080 и зловреден код на компютрите на други хора. 171 00:10:39,080 --> 00:10:42,910 Ето защо, ние не можем просто да използвате нашия наивен решение. 172 00:10:42,910 --> 00:10:45,590 Ние се нуждаят от начин да предпазим нашите програми от уязвими 173 00:10:45,590 --> 00:10:47,880 атака за препълване на буфера. 174 00:10:47,880 --> 00:10:51,430 За да направите това, трябва да се уверите, че нашият буфер може да расте както четем 175 00:10:51,430 --> 00:10:53,850 още информация от потребителя. 176 00:10:53,850 --> 00:10:57,440 Решението? Ние използваме куп заделените буфер. 177 00:10:57,440 --> 00:10:59,950 Тъй като ние да преоразмерите да го използвате за преоразмеряване презаделяне функция, 178 00:10:59,950 --> 00:11:04,580 и ние да следите на две числа - индексът на следващия празен слот в буфера 179 00:11:04,580 --> 00:11:08,390 и дължина или капацитет на буфера. 180 00:11:08,390 --> 00:11:13,210 Четем в символа от потребителя в даден момент използване на fgetc функция. 181 00:11:13,210 --> 00:11:19,360 Аргументът на fgetc функция е стандартния вход - е препратка към стандартния вход низ, 182 00:11:19,360 --> 00:11:23,810 което е preconnected входен канал, който се използва за прехвърляне на въвеждане на потребителя 183 00:11:23,810 --> 00:11:26,270 от терминала на програмата. 184 00:11:26,270 --> 00:11:29,890 >> Когато потребителят видове в нов герой, ние проверяваме, за да видите, ако индексът 185 00:11:29,890 --> 00:11:35,810 на следващия свободен слот плюс 1 е по-голяма от капацитета на буфера. 186 00:11:35,810 --> 00:11:39,690 Едно идва, защото ако на следващия свободен индекс е 5, 187 00:11:39,690 --> 00:11:44,150 дължина нашия буфер трябва да бъде 6 благодарение на 0 индексиране. 188 00:11:44,150 --> 00:11:48,350 Ако сме изчерпи пространството в буфер, а след това ние се опитваме да я оразмерите, 189 00:11:48,350 --> 00:11:51,690 удвоява, така че да можем ограничаване на броя пъти, че ние преоразмеряване 190 00:11:51,690 --> 00:11:54,760 ако потребителят пише в един наистина дълъг низ. 191 00:11:54,760 --> 00:11:57,950 Ако низът е намерила твърде дълго или ако бягаме от куп памет, 192 00:11:57,950 --> 00:12:01,350 ние освободим буфер и нула връщане. 193 00:12:01,350 --> 00:12:04,170 >> И накрая, ние добавяме Чар буфера. 194 00:12:04,170 --> 00:12:08,200 След като потребителят натисне влиза или да се върнат, сигнализация нов ред, 195 00:12:08,200 --> 00:12:12,050 или специален Чар - контрол г, което е сигнал за края на входа, 196 00:12:12,050 --> 00:12:16,240 правим проверка, за да се види, ако потребителят действително въвели в каквото и да било. 197 00:12:16,240 --> 00:12:18,820 Ако не, връщаме нула. 198 00:12:18,820 --> 00:12:22,280 В противен случай, защото нашият буфер е може би по-голям, отколкото ни е необходимо, 199 00:12:22,280 --> 00:12:24,830 в най-лошия случай това е почти два пъти по-голям, тъй като имаме нужда 200 00:12:24,830 --> 00:12:27,830 тъй като ние два пъти всеки път, когато преоразмерявате, 201 00:12:27,830 --> 00:12:31,840 правим ново копие на низа, само с помощта на размера на пространството, че имаме нужда. 202 00:12:31,840 --> 00:12:34,220 Ние добавяме допълнително 1 до изчистване разговор, 203 00:12:34,220 --> 00:12:37,810 , така че има място за специален символ нула терминатор - \ 0, 204 00:12:37,810 --> 00:12:41,990 които ние добавяме низ, след като копирате в останалата част от героите, 205 00:12:41,990 --> 00:12:45,060 използване strncpy вместо strcpy 206 00:12:45,060 --> 00:12:48,830 , така че да можем да определим точно колко символа искаме да копирате. 207 00:12:48,830 --> 00:12:51,690 Strcpy копира, докато го удари \ 0. 208 00:12:51,690 --> 00:12:55,740 Тогава ние освободим буфер и връща копието на повикващия. 209 00:12:55,740 --> 00:12:59,840 >> Кой знаеше, че такъв прост-привидна функция може да бъде толкова сложно? 210 00:12:59,840 --> 00:13:02,820 Сега вие знаете какво се случва в библиотеката CS50. 211 00:13:02,820 --> 00:13:06,470 >> Моето име е Нейт Hardison, и това е CS50. 212 00:13:06,470 --> 00:13:08,350 [CS50.TV]