[Powered by Google Translate] [CS50 Library]
[Nate Hardison] [Harvard Universiteit]
[Hierdie is CS50. CS50.TV]
Die CS50 biblioteek is 'n nuttige hulpmiddel wat ons op die toestel geïnstalleer
te maak dit makliker vir jou programme te kan skryf wat vinnige gebruikers vir insette.
In hierdie video, sal ons trek die gordyn terug en kyk na wat presies is in die CS50 biblioteek.
>> In die video op die C-biblioteke, ons praat oor hoe jy # headers lêers
van die biblioteek in jou bronkode,
en dan het jy 'n skakel met 'n binêre biblioteek lêer tydens die koppeling fase
van die samestelling.
Met die kopteksbeelde lêers spesifiseer die koppelvlak van die biblioteek.
Dit beteken dat hulle detail van al die hulpbronne wat die biblioteek beskikbaar vir jou om te gebruik,
soos funksie verklarings, konstantes, en data tipes.
Die binêre biblioteek lêer bevat die implementering van die biblioteek,
wat is saamgestel uit die biblioteek se header lêers en die biblioteek se c bron kode lêers.
>> Die binêre biblioteek lêer is nie baie interessant om te kyk want dit is goed, in binêre.
So, kom ons neem 'n blik op die kopteksbeelde lêers vir die biblioteek plaas.
In hierdie geval, daar is net een header lêer genaamd cs50.h.
Ons het dit in die gebruiker geïnstalleer, sluit directory
saam met die ander stelsel biblioteke header lêers.
>> Een van die eerste dinge wat jy sal sien, is dat cs50.h # sluit header lêers van ander biblioteke
float, limiete, standaard Bool, en standaard lib.
Weereens, na aanleiding van die beginsel van nie die wiel weer uitvind,
ons het die CS0 biblioteek met behulp van gereedskap wat ander vir ons gebou.
>> Die volgende ding wat jy sien in die biblioteek is dat ons 'n nuwe soort sogenaamde "string definieer."
Hierdie reël skep eintlik maar net 'n alias vir die tipe char *
sodat dit mettertyd nie kant die nuwe string tipe met eienskappe
algemeen geassosieer met die string voorwerpe in ander tale,
soos lengte.
Die rede waarom ons dit gedoen het, is om nuwe programmeerders te beskerm teen die gruwelike besonderhede
wysers totdat hulle klaar is.
>> Die volgende deel van die header-lêer is die verklaring van die funksies
dat die CS50 biblioteek verskaf saam met die dokumentasie.
Let op die vlak van detail in die kommentaar hier.
Dit is super belangrik sodat mense weet hoe om hierdie funksies te gebruik.
Ons verklaar, op sy beurt, funksioneer die gebruiker en terugkeer karakters, dubbels, dryf, ints aan te spoor,
lank verlang, en snare, met behulp van ons eie string tipe.
Na aanleiding van die beginsel van inligting wegkruip,
ons het ons definisie in 'n aparte c implementering lêer - cs50.c -
geleë in die gebruiker bron gids.
Ons het voorsien dat die lêer sodat jy kan 'n blik op dit,
leer uit dit, en heropstel dit op verskillende masjiene as jy wil,
selfs al het ons dink dit is beter om te werk op die toestel vir hierdie klas.
In elk geval, laat ons neem 'n blik op dit nou.
>> Die funksies getChar, GetDouble, GetFloat, getint, en GetLongLong
is almal gebou op die top van die GetString funksie.
Dit blyk dat hulle in wese almal volg dieselfde patroon.
Hulle maak gebruik van 'n while lus om die gebruiker vir 'n lyn van die toevoer te vinnig.
Hulle terugkeer 'n spesiale waarde indien die gebruiker 'n leë lyn insette.
Hulle probeer om die gebruiker se insette te ontleed as die toepaslike tipe,
word dit 'n char, 'n dubbel, 'n float, ens.
En dan sal hulle die resultaat terug indien die inset is suksesvol ontleed
of hulle reprompt die gebruiker.
>> Op 'n hoë vlak, is daar niks regtig lastig hier.
Jy kan insgelyks gestruktureerde kode geskryf het jouself in die verlede.
Miskien is die mees kriptiese-looking deel is die sscanf oproep wat die gebruiker se insette ontleed.
Sscanf is deel van die inset-formaat omskakeling familie.
Dit leef in standaard io.h, en sy werk is 'n C-string te ontleed,
volgens 'n spesifieke formaat, die stoor van die parse uitslae in veranderlike
wat deur die oproeper.
Sedert die invoer formaat omskakeling funksies is baie nuttig, wyd gebruik word funksies
wat nie super intuïtief op die eerste,
ons gaan oor hoe sscanf werk.
>> Die eerste argument te sscanf is 'n char * - 'n wyser na 'n karakter.
Vir die funksie om behoorlik te werk,
dat die karakter moet die eerste teken van 'n C-string,
beëindig met die null \ 0 karakter.
Dit is die string te ontleed
Die tweede argument te sscanf is 'n formaat string,
tipies as 'n string konstante geslaag,
en jy mag gesien het 'n string soos hierdie voor wanneer die gebruik van printf.
'N%-teken in die formaat string dui op 'n omskakeling specific.
Die karakter wat onmiddellik volg op 'n persentasie teken,
dui op die C-tipe wat ons wil sscanf te omskep.
In getint, sien jy dat daar is 'n% d en% c.
Dit beteken dat sscanf sal probeer om 'n desimale int -% d - en 'n char -% c.
Vir elke omskakeling specificatie in die formaat string,
sscanf verwag dat 'n ooreenstemmende argument later in sy argument lys.
Daardie argument moet verwys na 'n toepaslik getikte plek
wat die gevolg van die omskakeling te stoor.
>> Die tipiese manier om dit te doen is om 'n veranderlike te skep op die stapel voor die sscanf oproep
vir elke item wat jy wil om uit die string te parse
en gebruik dan die adres operateur - die ampersand - wysers te slaag
aan daardie veranderlikes aan die sscanf oproep.
Kan jy sien dat in getint ons presies dit doen.
Reg voor die sscanf oproep, verklaar ons 'n int n en 'n char oproep c op die stapel,
en ons verwysings na hulle slaag in die sscanf oproep.
Om hierdie veranderlikes op die stapel word verkies bo die gebruik van spasie
op die hoop met malloc, omdat jy die oorhoofse van die malloc oproep te vermy,
en jy hoef nie te bekommer oor die lek van geheue.
Karakters word nie voorafgegaan deur 'n persentasie teken gevra nie bekering.
Eerder hulle voeg net na die formaat spesifikasie.
>> Byvoorbeeld, as die formaat string in getint was 'n% d in plaas daarvan,
sscanf sal kyk vir die letter A, gevolg deur 'n int,
en terwyl dit poog om die int te omskep, sou dit nie doen nie enigiets anders met die a.
Die enigste uitsondering op hierdie spasie.
Wit spasie karakters in die formaat string ooreenstem met enige bedrag van spasie -
selfs glad nie.
So, wat is die rede waarom die kommentaar noem moontlik met die leiding en / of eindig met spasies.
So, op hierdie punt is dit lyk soos ons sscanf oproep probeer om die gebruiker se inset string te ontleed
deur te kyk vir moontlike Witruimte,
gevolg deur 'n int wat sal omgeskakel word en gestoor in die int veranderlike n
gevolg deur 'n bedrag van spasie, en gevolg deur 'n karakter
gestoor in die char veranderlike c.
>> Wat oor die terugkeer waarde?
Sscanf sal die inset lyn parse van begin tot einde,
stop wanneer dit die einde bereik of wanneer 'n karakter in die inset
kom nie ooreen met 'n formaat karakter of wanneer dit nie 'n sukses nie.
Dit se terugkeer waarde word gebruik om uitsonder wanneer dit opgehou.
As dit gestop het, omdat dit die einde van die inset string bereik
voordat hy enige doelskoppe en voor nie deel van die formaat string aan te pas,
dan die spesiale konstante EOF teruggestuur word.
Andersins, dit gee die aantal suksesvolle conversies,
wat kan wees 0, 1 of 2, aangesien ons het gevra vir twee doelskoppe.
In ons geval, ons wil om seker te maak dat die gebruiker in 'n int en slegs 'n int getik.
>> So, ons wil sscanf 1 om terug te keer. Sien waarom?
As sscanf teruggekeer 0, dan is geen bekerings gemaak is,
sodat die gebruiker ingetik iets anders as 'n int aan die begin van die insette.
As sscanf terugkeer 2, dan is die gebruiker het behoorlik tik dit in aan die begin van die insette,
maar hulle dan in sommige nie-spasie karakter getik daarna
sedert die% c sukses daarin geslaag.
Sjoe, dit is nogal 'n lang verduideliking vir een funksie oproep.
In elk geval, as jy meer inligting wil hê op sscanf en sy broers en susters,
check die man bladsye, Google, of albei.
Daar is baie van die formaat string opsies,
en dit kan red jy 'n baie van die handewerker wanneer ek probeer om stringe te ontleed in C.
>> Die finale funksie in die biblioteek om na te kyk, is GetString.
Dit blyk dat GetString is 'n moeilike funksie behoorlik te skryf,
selfs al is dit lyk asof so 'n eenvoudige, gemeenskaplike taak.
Hoekom is dit die geval?
Wel, laat ons dink oor hoe ons hier gaan om die lyn op te slaan dat die gebruiker tipes.
Aangesien 'n string is 'n volgorde van die karakters,
ons dalk wil om dit te stoor in 'n skikking op die stapel,
maar ons sou nodig het om te weet hoe lank die skikking gaan wees wanneer ons dit verklaar.
Net so, as ons wil om dit te sit op die wal,
ons nodig het om te slaag malloc die aantal grepe wat ons wil reserwe,
maar dit is onmoontlik.
Ons het geen idee hoeveel karakters sal die gebruiker tik
voor die aangesig van die gebruiker tik hulle eintlik nie.
>> 'N naïef oplossing vir hierdie probleem is om net te behou 'n groot stuk van die ruimte, sê,
'n blok van 1000 karakters vir die gebruiker se insette,
die veronderstelling dat die gebruiker nooit sou tik in 'n string wat lank.
Dit is 'n slegte idee om twee redes.
Eerstens, in die veronderstelling dat gebruikers tipies tik nie in stringe dat die lang,
jy kan mors nie 'n baie van die geheue.
Op die moderne masjiene, kan dit nie 'n probleem wees as jy dit doen
in een of twee geïsoleerde gevalle,
maar as jy die gebruiker se insette in 'n lus en stoor vir latere gebruik,
kan jy vinnig suig 'n ton van die geheue.
Verder, as die program wat jy skryf is vir 'n kleiner rekenaar -
'n toestel soos 'n smartphone of iets anders met 'n beperkte geheue -
hierdie oplossing probleme sal veroorsaak dat 'n baie vinniger.
Die tweede, meer ernstige rede om dit nie doen nie, is dat dit jou program verlaat kwesbare
wat genoem word 'n buffer oorloop aanval.
In programmering, 'n buffer geheue gebruik word om tydelik inset of uitset data stoor,
wat in hierdie geval is ons 1000-char blok.
'N buffer overflow voorkom wanneer data is verby die einde van die blok geskryf.
>> Byvoorbeeld, as 'n gebruiker tik in meer as 1000 karakters.
Jy dalk ervaar het dit per ongeluk wanneer programmering met skikkings.
As jy 'n verskeidenheid van 10 ints, niks stop jy van probeer om te lees of skryf nie
die 15de int.
Daar is geen saamsteller waarskuwings of foute.
Die program het net flaters reguit vorentoe en toegang tot die geheue
waar dit dink die 15de int sal wees, en dit kan jou ander veranderlikes oorskryf.
In die ergste geval, kan jy oorskryf sommige van jou program se interne
beheermeganismes, om werklik veroorsaak dat jou program uitvoer verskillende instruksies
as wat jy bedoel.
>> Nou, dit is nie algemeen is dit per ongeluk doen,
maar dit is 'n redelik algemene tegniek wat die slegte ouens gebruik om programme te breek
en kwaadwillige kode op ander mense se rekenaars.
Daarom kan ons nie net gebruik ons ​​naïef oplossing.
Ons moet 'n manier om te verhoed dat ons programme van kwesbare
aan 'n buffer oorloop aanval.
Om dit te kan doen, moet ons seker maak dat ons buffer kan groei soos ons lees
meer insette van die gebruiker.
Die oplossing? Ons gebruik 'n hoop toegekende buffer.
Aangesien ons dit kan die grootte van die gebruik van die grootte van die realloc funksie,
en ons hou van twee getalle - die indeks van die volgende leë slot in die buffer
en die lengte of die kapasiteit van die buffer.
Ons lees in die karakters van die gebruiker een op 'n tyd deur gebruik te maak van die fgetc funksie.
Die argument van die fgetc funksie neem - stdin - is 'n verwysing na die standaard inset string,
wat is 'n preconnected invoer kanaal wat gebruik word om die gebruiker se insette oor te dra
van die terminale na die program.
>> Wanneer die gebruiker tipes in 'n nuwe karakter, gaan ons om te sien of die indeks
van die volgende gratis slot plus 1 is groter as die kapasiteit van die buffer.
Die 1 kom in want as die volgende indeks is 5,
dan is ons buffer se lengte moet 6 danksy 0 kruip.
As ons het hardloop uit van die ruimte in die buffer, dan sal ons probeer om dit te resize,
te verdubbel sodat ons kap op die aantal kere wat ons die grootte van
indien die gebruiker in 'n baie lang string tik.
As die tou gekry het te lank, of as ons hardloop uit hoopgeheue,
ons vry om ons buffer en terugkeer null.
>> Ten slotte, ons voeg die kar aan die buffer.
Sodra die gebruiker treffers betree of terugkeer, die sein van 'n nuwe reël,
of die spesiale char - beheer d - wat dui op 'n einde van die insette,
ons doen 'n tjek te sien as die gebruiker eintlik getik in enigiets.
Indien nie, keer ons terug null.
Andersins, omdat ons buffer is waarskynlik groter as wat ons nodig het,
in die ergste geval dit is byna twee keer so groot as wat ons nodig het
aangesien ons elke keer as ons die grootte verdubbel,
maak ons ​​'n nuwe kopie van die string met behulp van die bedrag van die ruimte wat ons nodig het.
Ons voeg 'n ekstra 1 aan die malloc oproep,
sodat daar ruimte vir die spesiale null terminator karakter - die \ 0,
wat ons voeg aan die tou wanneer ons in die res van die karakters kopieer,
met behulp van strncpy in plaas van strcpy
sodat ons kan spesifiseer presies hoeveel karakters ons wil kopieer.
Strcpy afskrifte totdat dit tref 'n \ 0.
Dan sal ons vry om ons buffer en die standaard van die afskrif aan die oproeper.
>> Wie het geweet so 'n eenvoudige-oënskynlike funksie kan so ingewikkeld wees?
Nou weet jy wat gaan in die CS50 biblioteek.
>> My naam is Nate Hardison, en dit is CS50.
[CS50.TV]