[Powered by Google Translate] [CS50 Library]
[Nate Hardison] [Harvard University]
[To je CS50. CS50.TV]
Knihovna CS50 je užitečný nástroj, který jsme nainstalovali na spotřebiči
aby to pro vás jednodušší psát programy, které vyzve uživatele pro vstup.
V tomto videu, budeme zatáhněte oponu a podívat se na to, co přesně je v CS50 knihovně.
>> Ve videu na knihovny C, mluvíme o tom, jak si # include záhlaví soubory
v knihovně ve vašem zdrojovém kódu,
a pak propojit s binárním souboru knihovny během linkování fáze
z procesu kompilace.
Hlavičkové soubory specifikaci rozhraní v knihovně.
To znamená, že detail všech zdrojů, které má knihovna k dispozici pro vás k použití,
jako deklarace funkce, konstanty a datové typy.
Binární soubor knihovny obsahuje implementaci knihovny,
, který je sestaven z knihovny hlavičkové soubory a knihovny. c soubory zdrojových kódů.
>> Binární soubor s knihovnou není moc zajímavé podívat se na to, protože, no, v binárním formátu.
Takže, pojďme se podívat na hlavičkových souborů pro knihovnu místo.
V tomto případě je to pouze jeden hlavičkový soubor nazvaný cs50.h.
Jsme instalovali v uživatelské obsahovat adresář
spolu s hlavičkovým jiném systému knihoven souborů.
>> Jedna z prvních věcí, které si všimnete, je skutečnost, že cs50.h # obsahuje hlavičkové soubory z jiných knihoven -
float, limity, standardní bool a standardní lib.
Opět, podle zásady, že není objevování Ameriky,
jsme postavili CS0 knihovny pomocí nástrojů, které ostatní stanovené pro nás.
>> Další věc, kterou uvidíte v knihovně je, že my můžeme definovat nový typ nazvaný "string".
Tato linka opravdu jen vytváří alias char * typ,
takže to není magicky naplnit nový typ řetězce s atributy
obyčejně spojené s fazolovými objekty v jiných jazycích,
jako je délka.
Důvod, proč jsme udělali to je ochránit nové programátory z krvavých detailů
ukazatelů, dokud nebudou připraveni.
>> V další části záhlaví souboru je deklarace funkcí
že CS50 knihovna poskytuje společně s dokumentací.
Všimněte si, že úroveň podrobností v komentářích zde.
To je super důležité, aby lidé věděli, jak používat tyto funkce.
Prohlašujeme, v pořadí, funguje vyzvat uživatele a návratu znaků, dvoulůžkové, plave, Ints,
dlouho touží, a řetězce, s použitím vlastní typ řetězce.
V souladu se zásadou skrývání informací,
jsme dali naše definice v samostatném souboru implementace psaná v C -. cs50.c--
se nachází v adresáři uživatele zdroje.
Jsme za předpokladu, že soubor, takže můžete se podívat na to,
se z ní poučit, a překompilovat to na různých strojích, pokud si přejete,
i když si myslíme, že je lepší pracovat na zařízení této třídy.
Každopádně, pojďme se podívat na to teď.
>> Funkce getchar, GetDouble, GetFloat, GetInt, a GetLongLong
jsou postaveny na vrcholu GetString funkce.
Ukazuje se, že všichni řídit v podstatě stejný vzor.
Oni používají smyčky while vyzvat uživatele pro jeden řádek vstupu.
Oni se vrátí zvláštní hodnotu, pokud uživatel vstupy prázdným řádkem.
Snaží se analyzovat vstup uživatele jako vhodný typ,
ať už je to char, double, float, atd.
A pak buď vrátit, jestliže se vstup byl úspěšně analyzován
nebo se reprompt uživatele.
>> Na vysoké úrovni, není nic opravdu složité zde.
Možná jste napsal podobně strukturovaná kód sami v minulosti.
Snad nejvíce mystický vypadající část je sscanf volání, které analyzuje vstup uživatele.
Sscanf je součástí konverze vstupního formátu rodiny.
Žije v io.h standardní, a jeho úkolem je analyzovat řetězec C,
podle určitého formátu, ukládání rozebrat výsledky v proměnné
poskytuje volajícím.
Vzhledem k tomu, vstupní funkce pro konverzi formátů jsou velmi užitečné, široce používané funkce
že nejsou Super intuitivní nejprve,
půjdeme nad tím, jak sscanf funguje.
>> První argument sscanf je char * - ukazatel na znak.
Pro funkce pracovat správně,
že postava by měla být první znak z řetězce C,
ukončena s nulovým \ 0 znak.
Toto je řetězec analyzovat
Druhým argumentem sscanf je formátovací řetězec,
obvykle předána jako řetězcová konstanta,
a jste mohli vidět řetězec, jako je tento před při použití printf.
Znak procenta ve formátovacím řetězci označuje konverze specifikátor.
Charakter bezprostředně po znak procenta,
označuje typ C, které chceme sscanf převést na.
V GetInt, uvidíte, že tam je% d, a% c.
To znamená, že sscanf bude snažit desetinnou int -% d - a char -% c.
Pro každý typ konverze v parametru řetězec formátu,
sscanf očekává odpovídající argument, později v jeho seznamu argumentů.
Tento argument musí směřovat k odpovídajícím zadaný místě
do kterého se ukládají výsledek konverze.
>> Typický způsob, jak to udělat, je vytvořit proměnnou na zásobníku před voláním sscanf
pro každou položku, kterou chcete analyzovat z řetězce
a pak použijte adresu operátora - ampersand - projít odkazy
těchto proměnných do hovoru sscanf.
Můžete vidět, že v GetInt děláme přesně to.
Těsně před volání sscanf, jsme deklarovat int s názvem n a char volání C na zásobníku,
a míjíme ukazatele na ně do hovoru sscanf.
Uvedení těchto proměnných na zásobníku je přednostní přes používání prostor přidělený
na haldě s malloc, protože se vyhnete režii malloc volání,
a nemusíte se starat o úniku paměti.
Znaky nejsou předponou znakem procent nepobízejí konverzi.
Spíše se jen přidat k specifikaci formátu.
>> Například, v případě, že řetězec formátu v GetInt byly% d místo,
sscanf vypadat za písmenem a následuje int,
a když se pokusí převést int, to by nebylo nic jiného s A.
Jedinou výjimkou je mezera.
Bílé mezery ve formátovacím řetězci nalezeny žádné množství mezerou -
dokonce žádný vůbec.
Takže, to je důvod, proč komentář zmiňuje případně s předními a / nebo koncové mezery.
Takže, bude v tomto bodě to vypadá jako naše sscanf hovoru pokusí analyzovat uživatele vstupní řetězec
a kontrolovat případné vedoucí mezerou,
následuje int, která bude konvertována a uloženy v int proměnné n
následuje nějakého množství mezery, a následuje znak
uložen v proměnné char c.
>> Co návratové hodnoty?
Sscanf bude analyzovat vstupní řádku od začátku do konce,
zastavení, když dosáhne konce nebo když charakter ve vstupním
neodpovídá formátu charakter nebo pokud není možné uskutečnit převod.
Je to návrat hodnota se používá vyčlenit, když se zastavil.
Pokud se zastavil, protože na konci vstupního řetězce
před provedením jakékoli konverze a před tím, že zápas část formátovací řetězec,
pak speciální konstanta EOF je vrácena.
V opačném případě vrátí počet úspěšných konverzí,
, které by mohly být 0, 1 nebo 2, protože jsme požádáni o dvě konverze.
V našem případě chceme, aby se ujistil, že uživatel napsáno v int a pouze na int.
>> Takže, chceme sscanf vrátit 1. Podívejte se, proč?
Pokud sscanf vrátil 0, pak žádné převody byly provedeny,
takže uživatel napsal něco jiného než int na začátku vstupu.
Pokud sscanf vrátí 2, pak uživatel se řádně napište ji na začátku vstupu,
ale oni pak psali v nějakém non-prázdný znak poté
od% c převod úspěšný.
Wow, to je docela zdlouhavý vysvětlení jednom volání funkce.
Každopádně, pokud chcete více informací o sscanf a jeho sourozenci,
podívejte se na manuálové stránky, Google, nebo obojí.
Existuje spousta možností formátovacích řetězců,
a ty vám může ušetřit spoustu manuální práce, když se snaží analyzovat řetězce v jazyce C.
>> Konečná funkce v knihovně je podívat se na GetString.
Ukazuje se, že GetString je složité funkce psát správně,
i když se to zdá jako takový jednoduchý, společnému úkolu.
Proč je tomu tak?
No, pojďme si o tom, jak budeme ukládat řádek, že uživatel zadá v.
Vzhledem k tomu, řetězec je posloupnost znaků,
bychom mohli chtít uložit jej do pole na zásobníku,
ale potřebovali bychom vědět, jak dlouho pole bude, když jsme prohlásit ho.
Stejně tak, pokud chceme, aby to na hromadu,
musíme projít malloc počet bajtů chceme rezervy,
ale to je nemožné.
Nemáme ponětí, kolik znaků bude uživatel psát,
předtím, než uživatel skutečně nemá psát.
>> Naivní řešení tohoto problému je jen rezervovat velký kus prostoru, řekněme,
blok 1000 znaků pro vstup uživatele,
za předpokladu, že uživatel by nikdy zadat řetězec, který dlouho.
To je špatný nápad to ze dvou důvodů.
Za prvé, za předpokladu, že uživatelé obvykle nemají psát v řetězcích tak dlouho,
můžete odpad spoustu paměti.
Na moderních strojích, mohlo by to být problém, pokud to
v jednom nebo dvou ojedinělých případech,
ale pokud užíváte vstup uživatele do smyčky a skladování pro pozdější použití,
můžete rychle vysát spoustu paměti.
Navíc, pokud se program píšete je pro menší počítače -
zařízení, jako je smartphone, nebo něco jiného s omezenou pamětí -
toto řešení bude způsobovat problémy mnohem rychleji.
Druhý, vážnější důvod to udělat, je, že opustí svůj program zranitelné
na to, co se nazývá přetečení vyrovnávací paměti útok.
V programování, vyrovnávací paměť je paměť slouží k dočasnému ukládání vstupních nebo výstupních dat,
což v tomto případě je naše 1000-char blok.
Přetečení dochází při zápisu dat za koncem bloku.
>> Například, jestliže uživatel skutečně dělá typ ve více než 1000 znaků.
Možná jste to zažil náhodně při programování s poli.
Pokud máte řadu 10 ints, nic nezastaví vás z pokusu o čtení nebo zápis
15. int.
Nejsou žádné upozornění kompilátoru nebo chyby.
Program jen přehmatů rovně a přistupuje paměti
kde si myslí, že 15. int bude, a to může přepsat své další proměnné.
V nejhorším případě můžete přepsat některé z vašich programu vnitřní
kontrolní mechanismy, což váš program, aby skutečně provést různé instrukce
, než jste zamýšleli.
>> Nyní, to není běžné, aby to náhodou,
ale je to docela obyčejná technika, že protivníci používají rozbít programy
a dal škodlivého kódu na počítači jiných lidí.
Proto lze nejen použít náš naivní řešení.
Potřebujeme způsob, jak zabránit naše programy od bytí zranitelné
k přetečení vyrovnávací paměti útoku.
Chcete-li to, musíme se ujistit, že naše vyrovnávací paměti může růst, jak jsme si
více vstup od uživatele.
Řešení? Používáme haldy přidělené vyrovnávací paměti.
Vzhledem k tomu, můžeme změnit jeho velikost pomocí resize na realloc funkci,
a sledujeme ze dvou čísel - index dalšího prázdného slotu ve vyrovnávací paměti
a délka nebo kapacita pufru.
Čteme v znaků z uživatelského jeden po druhém pomocí fgetc funkci.
Argument fgetc funkce má - stdin - je odkaz na standardní vstupní řetězec,
který je preconnected vstupní kanál, který se používá pro přenos vstup uživatele
z terminálu do programu.
>> Kdykoli uživatel zadá do nového charakteru, můžeme zkontrolovat, zda index
dalšího volného slotu plus 1 je větší, než je kapacita vyrovnávací paměti.
1 je v, protože pokud příští zdarma index je 5,
pak naše vyrovnávací paměti délka musí být 6 díky 0 indexování.
Pokud jsme došly prostoru ve vyrovnávací paměti, pak se snažíme změnit jeho velikost,
zdvojnásobení to tak, že se snížit na to, kolikrát jsme velikost
v případě, že uživatel je psaní v opravdu dlouhé řetězce.
Pokud řetězec dostal příliš dlouho, nebo když narazíme z haldy paměti,
jsme osvobodit naše vyrovnávací paměti a vrátí hodnotu NULL.
>> Nakonec, přidáme char do vyrovnávací paměti.
Jakmile uživatel zmáčkne Enter nebo Return, což signalizuje nový řádek,
nebo speciální znak - kontrolní d - což signalizuje konec vstupu,
děláme Zkontrolujte, zda uživatel skutečně zadali vůbec nic.
Pokud ne, vrátíme null.
V opačném případě, protože náš vyrovnávací paměti je pravděpodobně větší, než potřebujeme,
v nejhorším případě je to téměř dvakrát tak velká jako je třeba
protože jsme dvakrát pokaždé, když jsme změnit velikost,
uděláme novou kopii řetězce, pouze pomocí množství prostoru, který potřebujeme.
Jsme přidat další 1 až malloc volání,
tak, že je prostor pro speciální nulový znak terminátoru - \ 0,
které přidáme do řetězce, jakmile budeme kopírovat ve zbytku postav,
pomocí strncpy místo strcpy
takže můžeme přesně určit, kolik znaků chceme kopírovat.
Strcpy kopíruje, dokud nenarazí na \ 0.
Pak jsme osvobodit naše vyrovnávací paměti a vrátí kopii volajícímu.
>> Kdo věděl, že takový jednoduchý vyhlížející funkce by měla být tak složité?
Teď už víte, co jde do CS50 knihovny.
>> Mé jméno je Nate Hardison, a to je CS50.
[CS50.TV]