[Powered by Google Translate] [CS50 Bibliothèque]
[Nate Hardison] [Université de Harvard]
[C'est CS50. CS50.TV]
La bibliothèque CS50 est un outil utile que nous avons installé sur l'appareil
pour le rendre plus facile pour vous d'écrire des programmes qui invitent les utilisateurs pour l'entrée.
Dans cette vidéo, nous allons tirer le rideau et regarde ce qui est exactement dans la bibliothèque CS50.
>> Dans la vidéo sur des bibliothèques C, on parle de la façon dont vous les fichiers # include têtes
de la bibliothèque dans votre code source,
et puis vous liez avec un fichier de bibliothèque binaire, durant la phase de liaison
du processus de compilation.
Les fichiers d'en-tête de spécifier l'interface de la bibliothèque.
Autrement dit, ils détaillent toutes les ressources que la bibliothèque dispose pour vous d'utiliser,
comme des déclarations de fonctions, constantes et types de données.
Le fichier de bibliothèque binaire contient la mise en œuvre de la bibliothèque,
qui est compilé à partir des fichiers d'en-tête de la bibliothèque et la bibliothèque pour les fichiers. code source C.
>> Le fichier de bibliothèque binaire n'est pas très intéressant à regarder car il est bien, en binaire.
Donc, nous allons jeter un oeil aux fichiers d'en-tête de la bibliothèque à la place.
Dans ce cas, il n'y a qu'un seul fichier d'en-tête appelé cs50.h.
Nous l'avons installé dans le répertoire include utilisateur
ainsi que les fichiers d'en-tête les bibliothèques du système des autres.
>> Une des premières choses que vous remarquerez est que cs50.h # includes fichiers en-tête provenant d'autres bibliothèques -
float, bool limites, standard, et lib standard.
Encore une fois, suivant le principe de ne pas réinventer la roue,
nous avons construit la bibliothèque CS0 l'aide des outils fournis que d'autres pour nous.
>> La prochaine chose que vous verrez dans la bibliothèque, c'est que nous définissons un nouveau type appelé "chaîne."
Cette ligne vraiment juste crée un alias pour le type char *,
de sorte qu'il ne devient pas magiquement imprégner le nouveau type de chaîne avec des attributs
souvent associé à des objets string dans d'autres langues,
comme la longueur.
La raison pour laquelle nous avons fait c'est de protéger les nouveaux programmeurs des détails sanglants
de pointeurs jusqu'à ce qu'ils soient prêts.
>> La prochaine partie du fichier d'en-tête est la déclaration des fonctions
que la bibliothèque CS50 offre ainsi que la documentation.
Notez que le niveau de détail dans les commentaires ici.
C'est super important que les gens sachent comment utiliser ces fonctions.
Nous déclarons, à son tour, agit pour demander à l'utilisateur et caractères de retour, doubles, flotteurs, entiers,
à long soupire, et cordes, en utilisant notre propre type de chaîne.
Suivant le principe de dissimulation d'information,
nous avons mis notre définition dans un fichier séparé la mise en œuvre c -. cs50.c--
situé dans le répertoire source de l'utilisateur.
Nous avons fourni ce fichier de sorte que vous pouvez jeter un oeil à elle,
apprendre de lui, et le recompiler sur des machines différentes si vous le souhaitez,
même si nous pensons qu'il est préférable de travailler sur l'appareil de cette classe.
Quoi qu'il en soit, nous allons jeter un coup d'oeil maintenant.
>> Les fonctions getchar, GetDouble, GetFloat, getInt, et GetLongLong
sont tous construits sur le dessus de la fonction GetString.
Il s'avère qu'ils suivent tous essentiellement le même modèle.
Ils utilisent une boucle while pour inviter l'utilisateur à une ligne d'entrée.
Elles retournent une valeur particulière si l'utilisateur entre une ligne vide.
Ils tentent d'analyser l'entrée de l'utilisateur dans le type approprié,
qu'il s'agisse d'un char, un double, un flotteur, etc
Et puis ils retournent le résultat soit si l'entrée a été correctement analysé
ou ils Nouvelle invite l'utilisateur.
>> À un niveau élevé, il n'ya rien de vraiment difficile ici.
Vous pourriez avoir écrit le code de structure similaire vous-même dans le passé.
Peut-être la partie la plus énigmatique est l'avenir de l'appel sscanf qui analyse l'entrée de l'utilisateur.
Sscanf fait partie de la famille de conversion format d'entrée.
Il vit dans io.h référence, dont le travail consiste à analyser une chaîne C,
selon un format particulier, stocker les résultats d'analyse dans la variable
fourni par l'appelant.
Comme les fonctions de conversion de format d'entrée sont très utiles, les fonctions couramment utilisées
qui ne sont pas super intuitif au premier abord,
nous allons passer en revue la façon dont fonctionne sscanf.
>> Le premier argument est un sscanf char * - un pointeur sur un caractère.
Pour que la fonction fonctionne correctement,
ce caractère doit être le premier caractère d'une chaîne de C,
terminé avec l'hypothèse nulle caractère \ 0.
Il s'agit de la chaîne à analyser
Le second argument de sscanf est une chaîne de format,
généralement transmis comme une constante chaîne,
et vous avez pu voir une chaîne comme ça avant lorsque vous utilisez printf.
Un signe pour cent dans la chaîne de format indique un spécificateur de conversion.
Le caractère qui suit immédiatement un signe pour cent,
indique le type C que nous voulons sscanf se convertir à l'.
En getInt, vous voyez qu'il ya un% d et un c%.
Cela signifie que sscanf va essayer à un int décimal - le d% - et un char -% c.
Pour chaque indicateur de conversion dans la chaîne de format,
sscanf attend un argument correspondant tard dans sa liste d'arguments.
Cet argument doit pointer vers un endroit approprié dactylographiée
dans lequel stocker le résultat de la conversion.
>> La façon habituelle de procéder est de créer une variable sur la pile avant l'appel sscanf
pour chaque élément que vous souhaitez analyser à partir de la chaîne
puis utilisez l'opérateur d'adresse - l'esperluette - à passer des pointeurs
de ces variables à l'appel sscanf.
Vous pouvez voir que dans getInt nous faire exactement cela.
Juste avant l'appel sscanf, nous déclarons un entier n et un appelé c appel caractères sur la pile,
et nous passons des pointeurs vers eux dans l'appel sscanf.
Mettre ces variables sur la pile est préférable à l'utilisation d'espace alloué
sur le tas avec malloc, puisque vous éviter le surcoût de l'appel malloc,
et vous n'avez pas à vous soucier de fuite de mémoire.
Les caractères non préfixé par le signe pour cent ne demande pas de conversion.
Au contraire, ils ne font qu'ajouter à la spécification de format.
>> Par exemple, si la chaîne de format dans getInt étaient d% au lieu,
sscanf serait chercher la lettre d'un suivi par un int,
et tandis qu'il tente de convertir le type int, il ne serait pas faire autre chose avec l'un.
La seule exception à cette règle est un espace.
Caractères blancs dans la chaîne de format correspond à aucune quantité d'espaces -
même pas du tout.
Donc, c'est pour cela que le commentaire évoque peut-être avec la direction et / ou les espaces de fin.
Donc, à ce stade, il ressemble à notre appel sscanf essaiera d'analyser chaîne d'entrée de l'utilisateur
en vérifiant premier espace possible,
suivie d'un int qui sera convertie et stockée dans la variable int n
suivie d'une certaine quantité d'espace, et suivi d'un caractère
stockés dans le répertoire c omble variable.
>> Qu'en est-il de la valeur de retour?
Sscanf va analyser la ligne d'entrée de bout en bout,
l'arrêt lorsqu'elle arrive à la fin ou lors d'un caractère en entrée
ne correspond pas à un caractère de format ou quand il ne peut pas faire une conversion.
Valeur de retour Il est utilisé pour identifier quand il s'est arrêté.
Si elle s'est arrêtée, car il a atteint la fin de la chaîne d'entrée
avant d'effectuer des conversions et avant d'échouer à correspondre à une partie de la chaîne de format,
alors la constante spéciale EOF est retournée.
Sinon, elle renvoie le nombre de conversions réussies,
qui peut être 0, 1 ou 2, étant donné que nous avons demandé deux conversions.
Dans notre cas, nous voulons faire en sorte que l'utilisateur a tapé dans un int et seulement un int.
>> Donc, nous voulons sscanf pour renvoyer 1. Voir pourquoi?
Si sscanf retourné 0, alors aucun conversions ont été faites,
si l'utilisateur a entré autre chose qu'un int au début de l'entrée.
Si sscanf renvoie 2, l'utilisateur a bien rempli le taper au début de l'entrée,
mais ils ont ensuite tapé dans un certain caractère non blanc après
depuis l'% c conversion a réussi.
Wow, c'est tout à fait une longue explication pour un appel de fonction.
Quoi qu'il en soit, si vous voulez plus d'informations sur sscanf et ses frères et sœurs,
consultez les pages de manuel, Google, ou les deux.
Il ya beaucoup d'options de chaîne de format,
et ceux-ci peuvent vous faire économiser beaucoup de travail manuel en essayant d'analyser des chaînes en C.
>> La dernière fonction dans la bibliothèque à regarder est GetString.
Il s'avère que GetString est une fonction difficile à écrire correctement,
même si elle semble comme une tâche simple et commun.
Pourquoi est-ce le cas?
Eh bien, nous allons réfléchir à la façon dont nous allons stocker la ligne que l'utilisateur tape po
Depuis une chaîne est une séquence de caractères,
nous pourrions le stocker dans un tableau sur la pile,
mais nous aurions besoin de savoir combien de temps le tableau va être quand on le déclare.
De même, si nous voulons le mettre sur le tas,
nous avons besoin de passer à malloc le nombre d'octets que nous voulons réserve,
mais cela est impossible.
Nous n'avons aucune idée du nombre de caractères que l'utilisateur va taper
avant que l'utilisateur ne fait de les taper.
>> Une solution naïve à ce problème est de simplement réserver une grande partie de l'espace, par exemple,
un bloc de 1000 caractères pour l'entrée de l'utilisateur,
en supposant que l'utilisateur n'aurait jamais taper une chaîne longue.
C'est une mauvaise idée pour deux raisons.
Premièrement, en supposant que les utilisateurs n'ont généralement pas taper dans les chaînes si longtemps,
vous pourriez perdre beaucoup de mémoire.
Sur les machines modernes, ce ne serait pas un problème si vous faites cela
dans un ou deux cas isolés,
mais si vous prenez entrée de l'utilisateur dans une boucle et stocker pour une utilisation ultérieure,
vous pouvez rapidement sucer une tonne de mémoire.
En outre, si le programme que vous écrivez est un petit ordinateur -
un dispositif comme un smartphone ou autre chose avec une mémoire limitée -
cette solution peut entraîner des problèmes beaucoup plus rapidement.
La seconde raison, plus grave de ne pas le faire, c'est qu'il laisse votre programme vulnérable
à ce qu'on appelle une attaque par débordement de tampon.
En programmation, un tampon est une mémoire utilisée pour stocker temporairement des données d'entrée ou de sortie,
qui dans ce cas est de notre chevalier 1000-bloc.
Un débordement de tampon se produit lorsque des données sont écrites après la fin du bloc.
>> Par exemple, si un utilisateur ne fait tapez plus de 1000 caractères.
Vous avez sans doute vécu ce accidentellement lors de la programmation avec les tableaux.
Si vous avez un tableau de 10 entiers, rien ne vous empêche d'essayer de lire ou d'écrire
l'int 15.
Il n'y a pas d'avertissements du compilateur ou d'erreurs.
Le programme seulement bévues, continuer tout droit et accède à la mémoire
où il pense que l'int 15e sera, et ce qui peut écraser vos autres variables.
Dans le pire des cas, vous pouvez remplacer certains des internes de votre programme
mécanismes de contrôle, l'origine de votre programme de réellement exécuter des instructions différentes
que vous le souhaitez.
>> Maintenant, ce n'est pas commun de le faire accidentellement,
mais c'est une technique assez répandue que les méchants utiliser pour briser des programmes
et mettre du code malveillant sur les ordinateurs des autres.
Par conséquent, nous ne pouvons pas utiliser notre solution naïve.
Nous devons trouver un moyen d'empêcher nos programmes d'être vulnérable
à une attaque par débordement de tampon.
Pour ce faire, nous devons nous assurer que notre tampon peut se développer comme nous le lisons
plus entrée de l'utilisateur.
La solution? Nous utilisons un tampon alloué tas.
Puisque nous ne pouvons redimensionner en utilisant le redimensionnement de la fonction realloc,
et nous gardons la trace de deux nombres - l'indice de la fente vide suivante dans la mémoire tampon
et la longueur ou de la capacité de la mémoire tampon.
Nous lisons dans les caractères de l'utilisateur un à la fois en utilisant la fonction fgetc.
L'argument de la fonction fgetc prend - stdin - est une référence à la chaîne d'entrée standard,
qui est un canal d'entrée préconnecté qui est utilisé pour transférer l'entrée de l'utilisateur
à partir de la borne à l'émission.
>> Chaque fois que l'utilisateur tape un caractère nouveau, nous vérifions pour voir si l'indice
de la fente à côté libre plus 1 est plus grand que la capacité de la mémoire tampon.
Le +1 est disponible en cause si le prochain index libre est de 5,
alors notre buffer de longueur doit être de 6 à 0 grâce indexation.
Si nous sommes à court d'espace dans la mémoire tampon, puis nous essayons de le redimensionner,
le doubler afin que nous réduisons le nombre de fois que nous redimensionner
si l'utilisateur tape dans une chaîne très longue.
Si la chaîne est devenu trop long ou si nous manquons de mémoire de tas,
nous libérer de notre tampon et return null.
>> Enfin, nous ajoutons le caractère à la mémoire tampon.
Une fois que l'utilisateur clique sur entrer ou revenir, signalant une nouvelle ligne,
ou le caractère spécial - le contrôle d - qui marque la fin de l'entrée,
nous faisons une vérification pour voir si l'utilisateur a effectivement tapé dans rien du tout.
Sinon, nous retourner null.
Dans le cas contraire, parce que notre tampon est probablement plus important que nous avons besoin,
dans le pire des cas, il est presque deux fois plus grand que nous devons
puisque nous doubler chaque fois que nous redimensionner,
nous faisons une nouvelle copie de la chaîne en utilisant juste la quantité d'espace dont nous avons besoin.
Nous ajoutons un 1 supplémentaire à l'appel malloc,
de sorte qu'il ya de la place pour le caractère spécial terminateur null - le \ 0,
dont nous joindre à la chaîne une fois que nous copier dans le reste des personnages,
en utilisant strcpy strncpy au lieu de
afin que nous puissions préciser exactement combien de caractères que nous voulons copier.
Strcpy copie jusqu'à ce qu'il rencontre un \ 0.
Ensuite nous libérons notre buffer et renvoie la copie à l'appelant.
>> Qui savait par exemple une fonction simple en apparence pourrait être si compliqué?
Maintenant, vous savez ce qui se passe dans la bibliothèque CS50.
>> Mon nom est Nate Hardison, et c'est CS50.
[CS50.TV]