[Powered by Google Translate] [CS50 Library]
[Nate Hardison] [Harvard University]
[Aquesta és CS50. CS50.TV]
La biblioteca CS50 és una eina útil que ens hem instal · lat al aparell
per fer més fàcil per a vostè per escriure programes que els usuaris sol · liciten dades.
En aquest vídeo, anem a estirar la cortina i mira el que exactament està a la biblioteca CS50.
>> En el vídeo en biblioteques C, parlem de com # include arxius de caps
de la biblioteca en el codi font,
i després connectar amb un arxiu de biblioteca binari durant la fase de vinculació
del procés de compilació.
Els arxius de capçalera especificar la interfície de la biblioteca.
És a dir, que detalli tots els recursos que la biblioteca té disponible per al seu ús,
com declaracions de funcions, constants i tipus de dades.
L'arxiu de biblioteca binari conté l'aplicació de la biblioteca,
que és una compilació dels arxius de capçalera de la biblioteca i les de la biblioteca. c fitxers de codi font.
>> L'arxiu de biblioteca binària no és molt interessant de veure, ja que és, bé, en binari.
Per tant, anem a fer una ullada als arxius de capçalera per a la biblioteca en el seu lloc.
En aquest cas, només hi ha un arxiu de capçalera anomenat cs50.h.
Ho hem instal · lat al directori d'usuari inclouen
juntament amb els arxius de capçalera de les biblioteques d'altres sistemes.
>> Una de les primeres coses que notarà és que cs50.h # inclou els arxius de capçalera d'altres biblioteques -
float, bool límits, estàndard, estàndard i lib.
Un cop més, seguint el principi de no reinventar la roda,
hem construït la biblioteca CS0 l'ús d'eines que proporcionen altres per a nosaltres.
>> El següent que veurem a la biblioteca és que es defineix un nou tipus anomenat "corda".
Aquesta línia realment només crea un àlies per al tipus char *,
pel que no torna imbuir al nou tipus de cadena amb atributs
comunament associats amb objectes de cadena en altres idiomes,
tals com la longitud.
La raó per la qual fem això és per protegir els nous programadors dels detalls sagnants
dels punters fins que estiguin llestos.
>> La següent part de l'arxiu de capçalera és la declaració de les funcions
que la biblioteca CS50 proporciona juntament amb la documentació.
Observeu el nivell de detall en els comentaris aquí.
Això és súper important perquè la gent sàpiga com utilitzar aquestes funcions.
Declarem que, al seu torn, funciona per sol · licitar a l'usuari i caràcters de retorn, dobles, carrosses, sencers,
llarg anhela, i les cordes, utilitzant el nostre propi tipus de cadena.
Seguint el principi d'ocultació d'informació,
hem posat la nostra definició en un arxiu d'execució separat c -. cs50.c--
ubicat al directori d'origen de l'usuari.
Hem proporcionat aquest arxiu per tu per fer una ullada a ell,
aprendre d'ella, i recompilar en màquines diferents si ho desitja,
tot i que crec que és millor treballar en l'aparell d'aquesta classe.
De tota manera, anem a fer una ullada ara.
>> Les funcions getchar, GetDouble GetFloat, getInt, i GetLongLong
es construeixen en la part superior de la funció GetString.
Resulta que tots segueixen essencialment el mateix patró.
Ells utilitzen un bucle while per sol · licitar a l'usuari una línia d'entrada.
Ells tornen un valor especial si l'usuari introdueix una línia buida.
S'intenta analitzar la entrada de l'usuari com el tipus adequat,
ja sigui un char, un doble, un flotador, etc
I llavors o bé tornar el resultat si l'entrada s'ha analitzat correctament
o reprompt l'usuari.
>> A un alt nivell, no hi ha res realment difícil aquí.
És possible que hagi escrit el codi d'estructura similar a tu mateix en el passat.
Potser la part més secreta d'aspecte és l'anomenada sscanf que analitza l'entrada de l'usuari.
Sscanf és part de la família d'entrada de conversió de format.
Viu en io.h estàndard, i el seu treball consisteix a analitzar una cadena C,
segons un format determinat, l'emmagatzematge dels resultats d'anàlisi en variables
proporcionat pel picador.
Atès que les funcions de conversió de format d'entrada són molt útils, les funcions utilitzades
que no són súper intuïtiu al principi,
anem a repassar com funciona sscanf.
>> El primer argument d'sscanf és un char * - un punter a un caràcter.
Perquè la funció funcioni correctament,
que el caràcter ha de ser el primer caràcter d'una cadena C,
acabar amb el nul caràcter \ 0.
Aquesta és la cadena per analitzar
El segon argument d'sscanf és una cadena de format,
normalment passa com una cadena constant,
i que podria haver vist una cadena com aquesta abans quan s'utilitza printf.
Un signe de percentatge en la cadena de format indica un especificador de conversió.
El caràcter immediatament després d'un signe de percentatge,
indica el tipus C que volem sscanf convertir.
En getInt, es veu que hi ha un d% i un% c.
Això vol dir que sscanf tractarà d'un decimal int - el% d - i aprofitar a - c%.
Per a cada indicador de conversió en la cadena de format,
sscanf espera un argument corresponent més endavant en la llista de paràmetres.
Aquest argument ha d'apuntar a una ubicació apropiada amb tipus
en què emmagatzemar el resultat de la conversió.
>> La forma típica de fer això és crear una variable a la pila abans de l'anomenada sscanf
per a cada element que voleu analitzar de la cadena
a continuació, utilitzeu l'operador de direcció - el signe - per passar punters
a les variables de l'anomenada sscanf.
Es pot veure que en getInt de fer exactament això.
Just abans de l'anomenada sscanf, declarem un enter anomenat n i aire anomenada carbó a la pila,
i passem punters a ells en l'anomenada sscanf.
Posant aquestes variables en la pila és preferible a utilitzar l'espai assignat
al munt amb malloc, ja que s'evita la sobrecàrrega de l'anomenada malloc,
i vostè no ha de preocupar-se per fuites de memòria.
Els personatges no precedits per un signe de percentatge no sol · liciten la conversió.
Més aviat, només ha d'afegir a l'especificació de format.
>> Per exemple, si la cadena de format en getint eren un d% en lloc,
sscanf buscaria la lletra A seguida d'un int,
i si bé s'intentarà convertir el int, no fer res més amb el a.
L'única excepció a això és l'espai en blanc.
Els espais en blanc en la cadena de format coincideix amb cap quantitat d'espai en blanc -
fins i tot cap en absolut.
Així que, per això el comentari esmenta possiblement amb la direcció i / o espais en blanc.
Per tant, en aquest moment sembla que la nostra crida sscanf tractarà d'analitzar la cadena d'entrada de l'usuari
mitjançant la comprovació de possibles espais en blanc,
seguit d'un int que es converteix i s'emmagatzema en la variable int n
seguit per una certa quantitat d'espai en blanc, i seguit per un caràcter
emmagatzemat en la variable c char.
>> Què passa amb el valor de retorn?
Sscanf analitzarà la línia d'entrada de principi a fi,
s'atura quan arriba al final o quan un personatge a l'entrada
no coincideix amb un caràcter de format o quan no es pot fer una conversió.
El seu valor de retorn s'utilitza per distingir quan es va aturar.
Si es va aturar, perquè ha arribat al final de la cadena d'entrada
abans de realitzar les conversions i abans de fallar perquè coincideixi amb part de la cadena de format,
llavors la constant EOF especial és retornat.
En cas contrari, retorna el nombre de conversions reeixides,
que pot ser 0, 1 o 2, ja que hem demanat dues conversions.
En el nostre cas, volem assegurar-nos que l'usuari va escriure en un enter i només un int.
>> Per tant, volem tornar a sscanf 1. Vegi per què?
Si sscanf trobat 0, llavors no hi ha conversions es van fer,
de manera que l'usuari ha escrit alguna cosa diferent d'un int al començament de l'entrada.
Si sscanf retorna 2, llavors l'usuari va tenir degudament escriviu en el començament de l'entrada,
però després es passen en algun caràcter que no sigui espai en blanc després
ja que el% c conversió va tenir èxit.
Wow, això és bastant llarga explicació per una crida a la funció.
De tota manera, si vols més informació sobre sscanf i els seus germans,
fes un cop d'ull a les pàgines de manual, de Google, o tots dos.
Hi ha un munt d'opcions de format de cadena,
i aquests poden estalviar una gran quantitat de mà d'obra quan es tracta d'analitzar cadenes en C.
>> L'última funció a la biblioteca per tenir en compte és GetString.
Resulta que GetString és una funció difícil d'escriure correctament,
tot i que sembla una tasca senzilla, comú.
Per què és aquest el cas?
Bé, anem a pensar en com anem a guardar la línia que l'usuari escriu polz
Atès que una cadena és una seqüència de caràcters,
el que es vol emmagatzemar en una matriu en la pila,
però necessitaríem saber quant temps la matriu serà quan ho declari.
De la mateixa manera, si volem posar-lo al munt,
hem de passar a malloc el nombre de bytes que desitja reservar,
però això és impossible.
No tenim idea de com molts caràcters que l'usuari escrigui en
abans que l'usuari realment es els escriu.
>> Una solució ingènua a aquest problema és simplement per reservar una gran part de l'espai, per exemple,
un bloc de 1000 caràcters per a l'entrada de l'usuari,
suposant que l'usuari mai hauria escriure en una cadena llarga.
Aquesta és una mala idea per dues raons.
En primer lloc, en el cas que els usuaris no solen escriure en les cadenes de tant de temps,
vostè podria perdre una gran quantitat de memòria.
En les màquines modernes, això podria no ser un problema si vostè fa això
en un o dos casos aïllats,
però si vostè està prenent l'entrada de l'usuari en un bucle i emmagatzemar per al seu ús posterior,
vostè pot absorbir una tona de memòria.
A més, si el programa que s'està escrivint és per a un equip més petit -
un dispositiu com un telèfon intel · ligent o alguna cosa més amb memòria limitada -
aquesta solució va a causar problemes molt més ràpid.
El segon motiu més greu per no fer-ho és que deixa el seu programa vulnerable
al que es diu un atac de desbordament de memòria intermèdia.
En programació, un buffer és la memòria utilitzada per emmagatzemar temporalment les dades d'entrada o sortida,
que en aquest cas és el nostre 1000-carbó bloc.
Un desbordament de memòria es produeix quan les dades s'escriuen més enllà del final del bloc.
>> Per exemple, si un usuari fa realment tipus en més de 1000 caràcters.
És possible que hagi tingut aquest accident quan es programa amb matrius.
Si vostè té un arranjament de 10 punts, res no impedeix intentar llegir o escriure
el int 15.
No hi ha advertències o errors del compilador.
El programa simplement errors de front i té accés a la memòria
on es creu que el int 15 serà, i això pot sobreescriure altres variables.
En el pitjor dels casos, pot sobreescriure alguns dels interns del seu programa
mecanismes de control, la causa del seu programa a executar realment diferents instruccions
que vostè pretén.
>> Ara, no és comú fer això per accident,
però aquesta és una tècnica bastant comú que els mals usen per trencar programes
i posar el codi maliciós en els ordinadors d'altres persones.
Per tant, nosaltres no podem usar la nostra solució ingènua.
Necessitem una forma d'evitar que els nostres programes de ser vulnerable
a un atac de desbordament de memòria intermèdia.
Per això, hem d'assegurar que el nostre buffer pot créixer a mesura que llegim
més informació de l'usuari.
La solució? Fem servir un munt memòria intermèdia assignat.
Com que podem canviar la seva mida utilitzant el canvi de mida de la funció realloc,
i fem un seguiment de dos nombres - l'índex de la ranura buida següent en el buffer
i la longitud o la capacitat de la memòria intermèdia.
Llegim en caràcters des de l'usuari alhora utilitzant la funció fgetc.
L'argument de la funció de presa fgetc - stdin - és una referència a la cadena d'entrada estàndard,
que és un canal d'entrada preconectado que s'utilitza per transferir la entrada de l'usuari
des del terminal al programa.
>> Cada vegada que l'usuari escriu en un nou personatge, comprovem si l'índex
de la ranura lliure següent més 1 és més gran que la capacitat de la memòria intermèdia.
L'un entra perquè si l'índex gratis al costat és de 5,
doncs el llarg nostre buffer ha de ser de 6 a 0 gràcies indexació.
Si ens hem quedat sense espai en el buffer, llavors intentem canviar la seva mida,
lo de manera que reduir el nombre de vegades que es canvia la mida
si l'usuari està escrivint en una cadena molt llarga.
Si la cadena s'ha fet massa llarg o si es queda sense memòria heap,
alliberem el nostre buffer i nul retorn.
>> Finalment, afegim el char a la memòria intermèdia.
Quan els accessos d'usuari ingressar o retornar, assenyalant una nova línia,
o l'especial de caràcters - Control d - el que indica un final de l'entrada,
fem una comprovació per veure si l'usuari realment escriure en res en absolut.
Si no, retorna null.
En cas contrari, ja que el nostre buffer és probablement més gran del que necessitem,
en el pitjor dels casos és gairebé dues vegades tan gran com cal
ja que es duplica cada vegada que canvia la mida,
es fa una nova còpia de la cadena amb la quantitat d'espai que necessitem.
Afegim un extra d'1 a l'anomenada malloc,
de manera que hi ha espai per l'especial caràcter nul terminador - el \ 0,
afegir a la cadena una vegada de copiar a la resta dels caràcters,
utilitzant strncpy en lloc de strcpy
de manera que podem especificar exactament com molts caràcters que voleu copiar.
Strcpy còpia fins que arriba a \ 0.
Llavors alliberem el nostre buffer i tornar la còpia a la persona que truca.
>> Qui sabia que aquesta funció aparentment simple podria ser tan complicat?
Ara vostè sap el que entra a la biblioteca CS50.
>> El meu nom és Nate Hardison, i això és CS50.
[CS50.TV]