[Jouer de la musique]
>> DOUG LLOYD: OK donc une suggestion avant de commencer ici.
Si vous ne l'avez pas regardé la vidéo sur pointeurs vous pouvez le faire en premier.
Parce que cette vidéo est un autre façon de travailler avec des pointeurs.
>> Donc, il va parler à propos de certains concepts
que nous couvrons dans le pointeurs vidéo, et nous sommes
va passer sur eux maintenant, en supposant qu'ils sont déjà
sorte de compris.
Voilà donc simplement votre avertissement juste que si vous voyez cette vidéo
et vous avez pas vu le pointeurs vidéo, il pourrait en quelque sorte
voler au-dessus de votre tête un peu.
Et ainsi il pourrait être mieux de le regarder dans cet ordre.
>> Donc, nous avons déjà vu un façon de travailler avec des pointeurs,
qui est, nous déclarons une variable, puis nous
déclarer une autre variable, un pointeur variable qui pointe vers elle.
Nous avons donc créé un variable avec un nom, nous avons
créé une seconde variable avec un nom, et nous soulignons que cette seconde variable
Lors de cette première.
Ce genre de a une problème cependant, car il
nous oblige à savoir exactement combien de mémoire nous sommes
allez avoir besoin du moment notre programme est compilé.
>> Pourquoi donc?
Parce que nous devons être en mesure de nommer ou identifier toutes les variables possibles
nous pourrions rencontrer.
Nous pourrions avoir un tableau qui pourrait être capable de tenir un grand nombre d'informations,
mais il est toujours pas exactement assez précis.
Que faire si nous ne savons pas, si nous avons aucune idée
combien nous aurons besoin d'au moment de la compilation?
Ou si Notre programme courir pour un temps très long,
accepter diverses utilisateur données, et nous ne pouvons pas vraiment
estimer si nous sommes allez avoir besoin de 1.000 unités?
>> Il est pas comme si nous pouvons dire à la ligne de commande
entrez le nombre d'éléments vous pensez que vous aurez besoin.
Eh bien si cette supposition est erronée?
Allocation dynamique de mémoire sorte de la façon dont nous permet
pour contourner ce problème particulier.
Et la façon dont il le fait est en utilisant des pointeurs.
>> Nous pouvons utiliser des pointeurs vers avoir accès à dynamiquement
mémoire allouée, mémoire qui est alloué que votre programme est en cours.
Il est pas attribué lors de la compilation.
Lorsque vous allouez dynamiquement mémoire, il vient d'une piscine
de mémoire connu sous le tas.
Auparavant toute la mémoire que nous avons travaille dans le cours
a été en provenance d'un pool de mémoire connu comme la pile.
Une bonne façon de général garder à l'mind-- et cette règle
ne tient pas toujours vrai, mais à peu près presque
maintient toujours true-- est que toute fois que vous donnez un nom variable, il
vit probablement sur la pile.
Et chaque fois que vous ne donner une variable un nom,
que vous pouvez faire avec la mémoire dynamique l'allocation, il vit sur le tas.
>> Maintenant, je suis une sorte de présenter cela comme si il ya ces deux pools de mémoire.
Mais vous avez peut-être vu cette diagramme, qui est généralement
une représentation de ce qui ressemble à la mémoire,
et on ne va pas se soucier de tous les les trucs dans le haut et le bas.
Qu'est-ce que nous nous soucions de cette partie est en le milieu ici, tas et de la pile.
Comme vous pouvez le voir par en regardant ce diagramme,
ce sont en fait deux pas piscines séparées de mémoire.
Il est une piscine partagée de mémoire où vous commencez, dans ce visuel
vous commencez au bas et commencer à remplir
à partir du bas de la pile, et vous commencer par le haut et commencer à remplir
de haut en bas avec le tas.
Mais il est vraiment le même pool, il est juste
différents endroits différents endroits, dans la mémoire qui sont alloués.
Et vous pouvez exécuter sur soit par mémoire comportant
le tas aller tout le chemin vers le bas, ou avoir
la pile aller tout le chemin vers le haut, ou présentant le tas et la pile
rencontrer un contre l'autre.
Tous ceux-ci peuvent être des conditions qui causent votre programme
à court de mémoire.
Alors garde cela en tête.
Lorsque nous parlons de le tas et de la pile
nous parlons vraiment de la même bloc général de la mémoire, tout simplement
que des parties différentes de la mémoire.
>> Alors, comment pouvons-nous obtenir dynamiquement mémoire allouée en premier lieu?
Comment obtenir notre programme la mémoire car il est en cours d'exécution?
Eh bien C fournit une fonction appelée malloc, allocateur de mémoire, ce qui
vous effectuez un appel, et vous passez dans combien d'octets de mémoire que vous souhaitez.
Donc, si votre programme est en marche et vous voulez un runtime entier,
vous pourriez Mallock quatre octets de mémoire, malloc parenthèses quatre.
>> Mallock passera par en regardant à travers le tas,
parce que nous sommes dynamiquement allouer de la mémoire,
et il reviendra à vous un pointeur vers cette mémoire.
Il ne vous donne pas que memory-- il ne donne pas de nom,
il vous donne un pointeur vers elle.
Et voilà pourquoi je l'ai dit à nouveau qu'il est important de peut-être
ont regardé la vidéo pointeurs avant d'aller trop loin dans cette.
Donc malloc va vous redonner un pointeur.
>> Si Mallock ne peut vous donner tout la mémoire parce que vous avez épuisé,
il va vous redonner un pointeur NULL.
Vous rappelez-vous ce qui se passe si nous essayer de déréférencer un pointeur NULL?
Nous souffrons d'un défaut de seg, non?
Voilà probablement pas bon.
>> Ainsi, chaque fois que vous faites un appel vous malloc toujours, toujours
besoin de vérifier si oui ou non la pointeur, il vous a donné est de retour nul.
Si elle est, vous devez mettre fin à votre programme parce que si vous essayez de déréférencer
le pointeur NULL vous allez souffrir d'une erreur de segmentation
et votre programme est nous écraser de toute façon.
Alors, comment avons-nous statiquement obtenir un nombre entier?
>> int x.
Nous avons probablement fait que un tas de fois, non?
Cela crée une variable appelée x qui vit sur la pile.
Comment pouvons-nous obtenir dynamiquement un nombre entier?
Int étoiles px égale malloc 4.
>> Ou plus appropriée nous dirions int étoiles px
est égal à la taille de malloc int, juste pour jeter un peu moins
nombres magiques autour de notre programme.
Cela va obtenir pour nous quatre octets de mémoire à partir du tas,
et le pointeur nous obtenons revenir est appelé px.
Et puis juste comme nous l'avons nous avons fait précédemment
peut déréférencer px à accéder à cette mémoire.
Comment pouvons-nous obtenir un nombre entier de l'utilisateur?
Nous pouvons dire int x est égal à obtenir int.
Voilà assez simple.
Que faire si nous voulons créer un tableau de X flotteurs qui vivent sur la pile?
flotter stack_array-- qui est le nom de nos array-- supports carrés x.
Cela créera pour nous un tableau de X flotteurs qui vivent sur la pile.
Nous pouvons créer un réseau de flotteurs qui vit sur le tas, aussi.
La syntaxe peut sembler un peu plus lourd,
mais nous pouvons dire flotteur heap_array étoiles égale
malloc x fois la taille du flotteur.
Je dois assez de place pour contenir x valeurs à virgule flottante.
Donc, dire que je dois 100 flotteurs, ou 1.000 flotteurs.
Donc, dans ce cas, il serait 400 octets pour 100 chars,
ou 4000 octets pour 1.000 flotteurs, parce que chaque flotteur prend
quatre octets d'espace.
>> Après avoir fait ce que je peux utiliser le crochet sur la syntaxe heap_array.
Juste comme je le ferais sur stack_array, je peut accéder à ses éléments individuellement
en utilisant heap_array zéro, une heap_array.
Mais rappeler la raison nous pouvons le faire est parce que le nom d'un tableau en C
est vraiment un pointeur vers premier élément de ce tableau.
Donc, le fait que nous allons déclarer une gamme de flotteurs sur la pile ici
est en fait un peu trompeur.
Nous sommes vraiment dans le deuxième ligne de code il
créant également un pointeur vers un morceau de mémoire que nous faisons ensuite un peu de travail avec.
>> Voici le gros problème avec la mémoire allouée dynamiquement si,
et cela est pourquoi il est vraiment important de développer des bonnes habitudes
lorsque vous travaillez avec elle.
Contrairement déclaré statiquement la mémoire, la mémoire
ne sont pas automatiquement retourné à la système lorsque votre fonction est fait.
Donc, si nous avons principale, et principale appelle une fonction
f, où f finitions tout ce qu'il fait et renvoie le contrôle du programme
Retour au menu principal, toute la mémoire que f utilisé est restitué.
Il peut être utilisé à nouveau par un autre programme,
ou une autre fonction que est appelée plus tard dans la principale.
Il peut utiliser la même mémoire encore.
>> Si vous dynamiquement allouer de la mémoire si
vous devez indiquer explicitement au système que vous avez fini avec lui.
Il va le retenir pour vous, ce qui pourrait conduire à un problème de vous manquer
de mémoire.
Et en fait, nous appelons parfois à cela comme une fuite de mémoire.
Et parfois, ces fuites de mémoire peut effectivement être vraiment dévastatrice
pour la performance du système.
>> Si vous êtes un utilisateur d'Internet fréquente vous pourriez utiliser certains navigateurs web,
et je ne vais pas citer de noms ici, mais il ya certains navigateurs web là-bas
qui sont connus pour avoir fait fuites de mémoire qui ne sont corrigés.
Et si vous laissez votre navigateur ouvert pour une très longue période de temps, jours
et des jours, voire des semaines, parfois vous peut-être remarqué que votre système
est en cours d'exécution vraiment, vraiment lentement.
Et la raison en est que le navigateur a alloué la mémoire,
mais alors pas dit le système qu'il a fait avec elle.
Et donc cela laisse moins de mémoire disponible pour tous vos autres programmes
d'avoir à partager, parce que vous êtes leaking-- ce navigateur web
programme est une fuite de mémoire.
Comment donnons-nous la mémoire de retour quand nous aurons fini avec elle?
Bien heureusement, il est un moyen très facile de le faire.
Nous venons de le libérer.
Il ya une fonction appelée libre, il accepte un pointeur vers la mémoire,
et nous sommes bon pour aller.
>> Donc, disons que nous sommes dans la milieu de notre programme,
nous voulons malloc 50 caractères.
Nous voulons malloc un tableau qui peut capable de contenir 50 caractères.
Et quand nous obtenons un pointeur sur que, le nom de ce pointeur est le mot.
Nous faisons tout ce que nous sommes va faire avec le mot,
et puis quand nous sommes fait nous venons de le libérer.
Et maintenant, nous avons retourné les 50 octets de mémoire au système.
Une autre fonction peut les utiliser.
Nous ne devons pas nous inquiéter à propos de la souffrance d'un fuite de mémoire parce que nous avons libéré mot.
Nous avons donné la mémoire de retour, de sorte que nous aurons fini de travailler avec elle.
Donc, il ya trois règles d'or qui devrait
être gardé à l'esprit chaque fois que vous êtes allocation dynamique de mémoire
avec malloc.
Chaque bloc de mémoire que vous devez être libéré malloc
avant que votre programme termine son exécution.
Maintenant, de nouveau, dans l'appareil ou dans le IDE arrive ce genre de toute façon pour vous
quand vous-- cela se produira de toute façon lorsque votre programme est terminé,
toute la mémoire sera publié.
Mais il est généralement bon codage la pratique de toujours, lorsque vous avez terminé,
libérez ce que vous avez mallocd.
>> Cela dit, les seules choses qui vous avez mallocd doit être libéré.
Si vous déclarez une statiquement entier, int x point-virgule,
qui vit sur la pile, vous ne veulent pas alors à x libérer.
Donc seules choses que vous avez mallocd doit être libéré.
>> Et enfin, ne pas quelque chose de gratuit deux fois.
Cela peut conduire à une autre situation bizarre.
Donc, tout ce que vous avez mallocd doit être libéré.
Seuls les choses que vous avez malloc doit être libéré.
Et ne pas quelque chose de gratuit deux fois.
>> Donc, nous allons passer par un exemple ici de ce que certains allouée dynamiquement
mémoire pourrait ressembler mixte avec un peu de mémoire statique.
Ce qui pourrait se produire ici?
Voyez si vous pouvez suivre long et devinez quoi est
va se passer comme nous allons à travers toutes ces lignes de code.
>> Donc, nous disons int m.
Qu'est-ce qu'il se passe ici?
Eh bien cela est assez simple.
Je crée une variable entière appelé m.
Je colore en vert, parce que ce la couleur
que je l'utilise quand je parle environ variables entières.
Il est une boîte.
Il est appelé m, et vous pouvez entiers de magasins à l'intérieur.
>> Que faire si je puis dire int étoiles un?
Eh bien ce est assez similaire.
Je crée une boîte appelée.
Il est capable de tenue int étoiles, des pointeurs vers des entiers.
Donc, je suis colorer en vert-ish ainsi.
>> Je sais qu'il a quelque chose à faire avec un nombre entier,
mais il est pas lui-même un nombre entier.
Mais il est à peu près la même idée.
Je ai créé une boîte.
Ces deux droit vivent maintenant sur la pile.
Je leur ai donné les deux noms.
>> int étoiles B est égal à la taille de malloc int.
Celui-ci pourrait être un peu délicat.
Prenez une seconde et de réfléchir à ce que vous serait attendre à arriver sur ce schéma.
int étoiles B est égal à la taille de malloc int.
>> Eh bien cela ne se crée pas une seule boîte.
Ceci crée en fait deux boîtes.
Et elle lie, il établit également un point dans une relation.
Nous avons alloué un bloc de la mémoire sur le tas.
Notez que la boîte en haut à droite il n'a pas de nom.
>> Nous mallocd elle.
Il existe sur le tas.
Mais b a un nom.
Il est une variable pointeur appelé b.
Qui vit sur la pile.
>> Donc, il est un morceau de la mémoire que les points les unes aux autres.
b contient l'adresse de ce bloc de mémoire.
Il n'a pas un nom autrement.
Mais il souligne à elle.
Donc, quand nous disons int étoiles B est égal à taille de malloc de int, ce droit là,
cette flèche qui a surgi sur la côté droit il, que toute chose,
Je vais le faire apparaître encore une fois, est ce qui se passe.
Tout cela se produit dans que seule ligne de code.
Maintenant, nous aurons un peu plus simple à nouveau.
une égale esperluette m.
Vous rappelez-vous ce qu'est un égale esperluette m est?
Eh bien voilà un obtient l'adresse de m.
Ou mettre plus schématiquement, quelques points à m.
>> A est égal à b.
OK alors voici une autre.
A est égal à b.
Ce qu'il va se passer le schéma, cette fois?
>> Eh bien rappeler que la œuvres de l'opérateur d'affectation
en affectant la valeur de la droit de la valeur du côté gauche.
Ainsi, au lieu d'un pointage à m, un maintenant des points au même endroit que les points b.
un ne pointe pas à B, Points Points où b.
>> Si un pointu pour B qui serait ont été un égal esperluette b.
Mais au lieu d'un égal b juste signifie que et b sont maintenant
pointant à la même adresse, parce l'intérieur de b est juste une adresse.
Et maintenant à l'intérieur d'un est la même adresse.
m est égal à 10, probablement le chose la plus simple
nous avons fait un petit peu.
Mettez le 10 dans la zone.
Star B est égal à m + 2, de rappeler signifie que notre pointeurs vidéo quelle étoile b.
Nous allons déréférencer b et de mettre une certaine valeur dans cet emplacement de mémoire.
Dans ce cas 12.
>> Alors, quand nous déréférencer un point de Rappelons que nous venons de descendre la flèche.
Ou autrement dit, nous aller à cette adresse mémoire
et nous manipulons en quelque sorte.
Nous avons mis une certaine valeur dans il.
Dans ce cas étoiles b est égal à 2 m plus est juste
aller à la variable pointée par b, aller à la mémoire pointée par b,
et de mettre m plus 2 là, 12.
>> Maintenant je libre b.
Qu'advient-il lorsque je libère b?
Se souvenir de ce que je disais des moyens gratuits.
Que dis-je quand je gratuit B?
>> Je suis fait de travailler avec elle, non?
Je donne l'essentiel de la mémoire.
Je lui donne en retour au système.
Je ne pas besoin de ça est plus ce que je leur dis, OK?
>> Maintenant, si je dis une étoile est égal à 11, vous pouvez probablement
dire déjà que quelque chose de mauvais qui va se passer ici, non?
Et en effet, si je voulais que je doute subirait une erreur de segmentation.
Parce que maintenant, bien que précédemment que partie de mémoire
était quelque chose que je devais l'accès à, à ce stade
maintenant je accéder à la mémoire que est pas légal pour moi d'accéder.
>> Et comme nous allons probablement rappeler, quand on accéder à la mémoire
que nous ne sommes pas censés toucher, qui est la cause la plus fréquente
d'une segmentation faute. Et si mon programme
échouerait si je essayé de le faire.
Encore une fois, il est une bonne idée pour obtenir une bonne pratiques et de bonnes habitudes enracinées
lorsque vous travaillez avec malloc et free, de sorte que vous ne souffrez pas de segmentation
défauts, et que vous utilisez votre allouée dynamiquement
la mémoire de façon responsable.
>> Je suis Doug Lloyd cela est CS50.