Bonjour et bienvenue à nouveau.
Dans cette conférence, je veux parler du cas d'utilisation
des pointeurs lorsque nous allons les utiliser comment nous allons les utiliser Nous savons comment les créer.
les déclarer et les définir.
Nous savons leur attribuer l'adresse d'une variable existante à l'aide de l'adresse de l'opérateur.
Et nous savons comment les dé-référencer,
comment obtenir la valeur vers laquelle pointe le pointeur.
Maintenant, comment pouvons-nous commencer à les utiliser.
Donc c propose plusieurs opérations de base que vous pouvez effectuer sur les pointeurs.
Vous pouvez attribuer une adresse à un pointeur
que nous avons déjà appris.
Il s'agit d'une variable existante où la variable a une adresse.
Et vous regardez simplement l'adresse de cette variable en utilisant l'adresse de l'opérateur, et nous
avons un point à cela. Nous pourrions également affecter un pointeur existant à un autre pointeur.
Vous pouvez attribuer une adresse à un pointeur de deux manières.
Cela peut donc être un nom de tableau en lui-même.
Nous n'avons pas encore parlé des tableaux, mais lorsque vous attribuez une augmentation à
un pointeur, il vous suffit de spécifier le nom. Vous n'avez même pas besoin d'utiliser l'adresse de l'opérateur.
Jusqu'à présent, nous nous sommes simplement concentrés sur l'utilisation d'une variable existante
et la transmission de l'adresse de la variable elle-même.
Mais les 3 façons dont vous pouvez le faire sont mentionnées ici.
Vous pouvez également déréférencer un pointeur. Nous venons d'apprendre que c'est là que vous
utilisez, l'astérisque l'opérateur d'indirection.
Cela vous donnera la valeur stockée dans le pointeur vers. Le pointeur la valeur du pointeur
qui est une adresse vers laquelle pointe le
point, utilisez-la simplement. Vous pouvez également prendre une adresse de pointeur.
Il s'agit de l'adresse réelle du pointeur lorsque vous créez le
pointeur où le pointeur lui-même est stocké.
Vous pouvez également utiliser l'adresse que j'ai sur ce pointeur.
Et vous pouvez également effectuer l'arithmétique du pointeur. Nous allons avoir une conférence séparée à ce sujet.
C'est ici que vous pouvez utiliser les opérateurs plus
et moins pour ajouter des entiers à un pointeur ou soustraire des entiers à un pointeur.
Et cela vous permet d'avoir une notation spécifique et vous permet
de sauter plus rapidement dans la mémoire, surtout si vous utilisez des tableaux.
Donc, ce que vous faites généralement, c'est que lorsque vous ajoutez un
entier à un pointeur à
l'aide de l'opérateur plus,
il va simplement définir l'adresse de ce pointeur sur autant d'octets.
Si vous soustrayez
un nombre d'un pointeur, il va
définir cette adresse en moins un certain nombre d'octets.
Vous pouvez également incrémenter de un, et
vous verrez que c'est très courant lorsque nous l'utilisons dans des tableaux.
Ainsi, lorsque vous êtes dans un tableau et que vous souhaitez passer à l'élément suivant au lieu d'utiliser l'index,
vous pouvez utiliser un pointeur et l'incrémenter simplement de un.
Si vous souhaitez passer à l'élément précédent au lieu d'utiliser un index, vous pouvez
simplement le décrémenter en pointant de un.
Donc l'arithmétique des pointeurs, nous allons parler exclusivement, mais c'est quelque
chose que vous pouvez faire avec des pointeurs.
Et encore une fois, c'est une notation particulière qui permet de se
déplacer rapidement en mémoire, d'être
plus efficace.
Vous pouvez également trouver la différence entre 2 pointeurs.
Donc, si vous avez 2 pointeurs et que les éléments sont dans le même
tableau, vous voudrez peut-être savoir à quelle distance
ils sont, les éléments, vous pouvez les réduire.
Ce serait la différence de
2 pointeurs et. Donc, si vous êtes index 5 et
que vous aviez un pointeur dans l'index 5, vous aviez un autre point
pointant vers l'index 15, vous pourriez les
moins et cela
vous donnerait combien d'éléments ils sont absents, car ce serait l'adresse hexadécimale moins
l'autre adresse hexadécimale en supposant le tableau en mémoire
continue qu'il est, il affichera à quelle distance ils sont.
Vous pouvez utiliser des opérateurs relationnels pour comparer les valeurs de 2 pointeurs.
Les pointeurs doivent être du même type. Donc, s'ils pointent tous les deux des entiers, ils doivent tous
deux être du même type.
Cela va simplement vous dire si les adresses sont supérieures ou inférieures à.
Encore une fois, vous pouvez identifier la partie du tableau dans laquelle vous vous trouvez.
Il existe également 2 formes de soustraction.
Donc, je viens de parler de
soustraction où vous pouvez réellement prendre un pointeur et le soustraire d'un
autre que vous
obtiendrez un pointeur ou vous pouvez soustraire un pointeur
d'un entier, ce qui vous donnera un pointeur.
Soustrayez donc un pointeur d'un autre pour obtenir un entier ou
soustrayez un entier d'un pointeur pour obtenir un pointeur. Ce sont les 2 cas.
Nous garderons donc à l'esprit que nous passerons par d'autres exemples.
Soyez prudent lorsque vous utilisez l'incrémentation ou la décrémentation de pointeurs et
que le tableau est hors limites. Donc, la plupart des choses que vous faites
avec l'arithmétique des pointeurs se produisent lorsque vous travaillez sur des tableaux.
Car encore une fois, ça permet de se déplacer rapidement, c'est une syntaxe simple.
Mais rappelez-vous, les tableaux ont une erreur hors limites.
Donc, si vous incrémentez trop loin, vous allez
sortir des limites du tableau. Si vous décrémentez trop loin, vous
allez avoir un sous les limites, vous entrez dans un nombre négatif.
L'ordinateur lui-même ne va pas savoir si un pointeur pointe toujours vers un élément du tableau.
Donc, en utilisant le point de l'arithmétique sur les tableaux, vous devez être prudent.
Si vous souhaitez utiliser des pointeurs dans les expressions, vous pouvez également le faire.
Nous en avons donc parlé un peu plus tôt, et nous avons déréférencé le pointeur et nous en
avons ajouté 15. Je pense que nous en avons 20.
Ainsi, la valeur du pointeur pi peut être utilisée dans les expressions arithmétiques.
Donc, si une variable est définie comme étant de type pointeur vers entier,
alors elle est évaluée en utilisant les règles de l'arithmétique entière.
Et nous l'avons montré avec la déréférence. Donc, si vous avez
une variable et que vous avez un pointeur, initialisez-le à null, vous signez alors
votre pointeur à l'adresse de cette variable. Vous pouvez alors simplement dire le nombre d'étoiles plus égal à 25.
N'oubliez pas que le nombre d'étoiles obtient la valeur vers laquelle pointe.
Donc ce que cela fait, c'est dire que la valeur de pnumber
est égale à la valeur pnumber plus 25.
La valeur sera donc égale à 35.
Cela ne change pas ce sur quoi il pointe parce que nous utilisons un astérisque, donc cela ne
change pas l'adresse vers laquelle nous pointons, cela
ne change pas l'adresse elle-même parce que nous n'avons pas l'adresse de l'opérateur.
Nous changeons la valeur vers laquelle il pointe.
Donc, en incrémentant la valeur de la variable number de 25, l'étoile indique que
vous demandez le contenu vers lequel pointe la variable appelée pnumber.
Si un pointeur pointe sur la variable x, ce pointeur
a été défini pour être un pointeur vers le même type de données que x.
Donc, si vous créez un pointeur de fin un pointeur flottant,
vous ne pouvez avoir qu'une adresse
d'un type de données qui est float ou int selon celui que vous avez déclaré.
Ainsi, l'utilisation de l'opérateur d'indirection dans une
expression est identique à l'utilisation de x dans la même expression.
Et c'est tout ce qu'il dit, c'est que si vous utilisez un float ou que vous
avez un int et que vous utilisez l'opérateur d'indirection, vous le déréférencer, vous pouvez
faire tout ce que vous pouvez si vous avez un float dedans, quoi qu'il pointe.
Une variable définie comme un pointeur vers un int peut stocker l'adresse de n'importe
quelle variable de type in, on le sait.
Donc, ici, la valeur int est égale à 999, nous pouvons affecter cet int à
pnumber tant que pnumber est un pointeur vers un int, puis
nous pouvons y ajouter.
L'instruction fonctionnera avec la nouvelle valeur de variable
et la nouvelle valeur de contenu sera 1024.
Pnumber pointe vers la valeur, l'adresse
de la valeur. Donc, si vous changez la valeur du
pointeur vers laquelle il pointe, vous allez changer la valeur de cette valeur de variable.
Alors rappelez-vous simplement que c'est le concept de changer une variable à un endroit
du pointeur et que vous le changez en plusieurs variables.
Un pointeur peut contenir l'adresse de n'importe quelle variable du type approprié.
Vous pouvez donc utiliser une variable de pointeur pour modifier les valeurs de nombreuses variables différentes s'il y
a des entiers, des doubles ou des flottants. Tant qu'ils sont du type compatible avec le type
de pointeur, vous pouvez modifier cette valeur. Vous ne pouvez pas modifier la
valeur de pnumbers si pnumber pointe vers un flottant et que la
valeur est un entier. Vous ne pourriez pas faire ça. Vous auriez une erreur de compilation.
Un autre exemple ici. Ici, nous allons vous
montrer comment obtenir l'adresse de certaines variables. Donc, ici, dans cette main, nous
faisons une arithmétique
de pointeur sur les expressions réelles.
Donc, nous ne faisons rien sur un tableau, donc nous n'incrémentons ni ne
décrémentons les pointeurs. Nous décrémentons donc les valeurs. Nous avons donc 2
types longs num1 et num2 puis nous avons un pointeur de type long, nous l'initialisons à null.
Nous attribuons l'adresse de num1 à notre pointeur pnum.
Et puis nous attribuons la valeur de pnum à L,
ce qui signifie que num1 va maintenant être 2l.
Si nous incrémentons num2, maintenant num2 n'a encore
rien fait.
La valeur de pnum est donc 2l, cela signifie que la valeur de num1 est 2l.
L est juste le suffixe pour signifier que c'est un long.
Si nous incrémentons maintenant la valeur longue num2, c'est
0l, ça va être 1l.
Si nous disons que num2 plus est
égal à star pnum, pnum vaut 2l, donc ça va
être 1l plus 2l, num2 va maintenant être égal à 3l.
Et puis si nous attribuons l'adresse de num2 à pnum, pnum
va maintenant être égal à l'adresse de num2.
Donc, si nous incrémentons pnum
ce que nous désignons, nous allons maintenant avoir 4l.
Et nous allons regarder cela à l'intérieur des blocs froids, mais
je vous guide à travers cela. Num1 va être égal à 2l.
Num2 va être égal à ce qu'il
pointe vers pnum.
Pnum est 3l, donc je pense que ça va être 3l.
Pnum sera de 3l, puis pneum plus num2 sera
de 6l.
Voyons donc si j'ai raison, parcourez cela en blocs de code.
Nous voici donc dans des blocs de code, nous avons essayé de parcourir cela à la main,
mais maintenant nous voulons voir si nous avons raison. Utilisons le débogueur.
Nous allons mettre cela ici et nous verrons en parcourant le programme comment les valeurs changent.
Alors construisons ceci et débogageons-le.
Cela va démarrer et s'arrêtera à la ligne 10.
Et si nous ouvrons notre fenêtre de surveillance, ce que nous
pouvons faire en procédant au débogage dans les fenêtres, les montres, les montres, nous pouvons voir
les valeurs au fur et à mesure. Donc, pour le
moment, num1 est zéro, num2 est zéro, pnum pointe vers null.
C'est pourquoi il s'agit de
0x0, car nous savons que null représente 0 en nombre.
Et nous pouvons l'utiliser lorsque nous le comparons dans des déclarations if.
Donc, après avoir exécuté la ligne 10, pnum devrait maintenant avoir l'adresse de num1.
Alors passons un peu plus.
Maintenant, pnum a une adresse réelle 0x60ff08.
Après avoir exécuté la ligne 11, nous allons dire que la valeur de pnum est égale à 2l, et nous ne verrons
rien dans la fenêtre de surveillance pour cela. Mais allons-y et exécutons-le, pnum a
toujours la même adresse.
Num1 est maintenant changé car pnum avait l'adresse
de num1, et nous l'avons changé.
Alors maintenant num1 est 2. Maintenant aux lignes 12, nous allons incrémenter num2.
Donc num2 va juste devenir 1l.
Ça va être 1. L'adresse de pnum est toujours la même.
Maintenant, nous allons ajouter à num2 ce
qu'était pnum. Rappelez-vous que Pnum
pointe vers num1, donc num2 doit être 3.
Ensuite, nous passons à 14, num2 est 3, num1 est toujours 2.
Maintenant, à la ligne 15, nous allons
attribuer à pnum une nouvelle adresse de num2. Donc, après
cela, nous n'allons plus être 0x60ff08.
Nous allons être 060ff04.
Donc maintenant, si nous incrémentons la valeur pointée par pnum qui est le numéro 2
et le numéro 2 est 3, le numéro 2 devrait maintenant être 4.
Et nous voyons que c'est 4.
Maintenant, nous allons imprimer toutes ces valeurs et vous allez voir que la valeur de num1
devrait être 2.
La valeur de num2 doit être 4.
Pnum pointe vers num2, donc cela devrait toujours être 4.
Et puis nous allons dire la valeur de pnum qui est 4 plus,
num2 qui est 4 devrait être 8.
Donc, j'aurais peut-être été avec 6.
Alors maintenant, nous ne pourrons pas voir cela dans la fenêtre de surveillance. Alors jouons-le et
voyons la sortie sous forme d'instructions printf. Nous devrions voir 2448.
Alors exécutons ceci maintenant en mode non débogué,
et nous voyons 2 4 4 8.
Alors on y va. J'espère que cela a du sens.
Revenons en arrière et continuons notre discussion.
Alors que diriez-vous lorsque nous recevons des commentaires, comment pouvons-nous utiliser des pointeurs de cette manière.
Jusqu'à présent, lorsque nous utilisons scanf pour saisir des valeurs, nous devons utiliser l'opérateur esperluette chaque fois que
nous avons un type de données inter ou float. Le seul moment où nous l'avons, c'est lorsque nous
avons un tableau de caractères et la raison en est que le caractère a
est en fait un pointeur de caractère dont nous allons parler.
Mais si nous utilisons scanf pour saisir des valeurs et que nous les utilisons sur des types
de données normaux qui ne sont pas des tableaux de caractères, nous avons toujours dû utiliser cet opérateur add ou sub.
Et la raison en est que le deuxième argument de scanf est un pointeur.
Nous devons donc lui envoyer une adresse. Les pointeurs n'ont que des valeurs d'adresses.
Ainsi, lorsque vous avez un pointeur qui contient déjà une adresse, vous pouvez utiliser le nom du pointeur comme argument pour scanf.
Vous n'avez donc pas besoin d'utiliser l'opérateur esperluette si vous avez réellement créé un
pointeur, car le deuxième argument du scanf est un pointeur et vous pouvez donc
simplement dire le nom du pointeur.
Dans le passé, si nous voulions stocker une valeur en
valeur, nous aurions dit
valeur esperluette dans le deuxième argument de scanf.
Mais si nous avons un pointeur que nous créons et qu'il pointe déjà
vers une adresse comme dans cet exemple,
alors lorsque nous utilisons scanf, tout ce que nous avons à dire est le nom de la
valeur, le nom du pointeur.
Voici donc un cas où nous avons un entier, mais nous
n'avons pas besoin d'utiliser une esperluette car nous avons un pointeur vers un entier.
Nous disons simplement pour cent d, valeur p.
Donc, il y a d'autres moments où vous pouvez passer
des noms réguliers de variables à scanf en plus des tableaux de caractères si
vous avez un pointeur.
Vous pouvez également imprimer ce qu'ils ont entré par la suite et vous remarquerez
que la valeur va en fait être changée en ce qu'ils ont
entré parce que nous pointons vers cette adresse.
Test de null.
Il y a une règle que vous devez graver dans votre mémoire. C'est très très important.
Nous avons parlé de déréférencement, mais que se passe-t-il si vous déréférencer un
pointeur non intentionnel, un pointeur qui ne pointe vers rien
ou un pointeur qui n'a pas de mémoire allouée.
Alors que faire si nous faisons quelque chose comme ça. Nous déclarons un pointeur,
mais nous ne l'avons jamais réellement initialisé, puis nous essayons de lui assigner.
Nous dé-référencons et y attribuons, c'est une grosse erreur.
Donc, la deuxième ligne signifie essentiellement que vous
voulez stocker la valeur 5 à l'emplacement vers lequel pointe
pt, mais pt ne pointe vers rien car il n'a pas été initialisé.
Donc pt va maintenant avoir une valeur aléatoire.
On ne sait donc pas où 5 sera placé, il pourrait être placé n'importe où dans la mémoire.
Cela pourrait être inoffensif. Il peut surpasser
les données existantes ou les variables d'état existantes dans votre programme.
Cela pourrait provoquer le blocage du programme. C'est très problématique.
Ainsi, lorsque vous créez un pointeur et que vous allouez de la mémoire pour stocker le pointeur lui-même, il
n'alloue pas de mémoire pour stocker les données.
Donc en disant instar pt, cela a
alloué de la mémoire pour le pointeur, mais il
n'a alloué aucune mémoire pour quoi pour la
valeur du pointeur, l'adresse. N'oubliez pas que les pointeurs contiennent des adresses.
Il a créé le pointeur mais il n'a pas créé de mémoire pour ce qu'il pointe.
Vous ne pouvez donc pas le déréférencer.
Il n'alloue donc pas de mémoire pour stocker les données.
Avant d'utiliser un pointeur, il faut lui attribuer un emplacement mémoire qui a déjà été
alloué ou vous devez utiliser l'allocation de mémoire dynamique à l'aide de malloc dont
nous parlerons Donc, soit vous attribuez l'adresse d'une variable existante au pointeur,
soit vous utilisez malloc qui est l'allocation de mémoire dynamique.
Mais gardez cela à l'esprit chaque fois que vous utilisez un pointeur si vous l'avez
créé et qu'il était nul, vous voulez le vérifier au préalable
pour null, nous en parlerons dans une seconde. Mais si vous avez créé un
pointeur qui n'a pas été initialisé, ne lui attribuez rien à
moins qu'il ne pointe vers une autre variable initialisée de cette façon ou que la mémoire soit allouée.
C'est donc là que null entre en jeu.
Vous pouvez en fait tester null pour vous assurer
que vous n'avez pas d'erreur de déréférence. Assurez-vous que votre programme ne plante pas.
Nous savons donc déjà que null ne pointe fondamentalement
vers rien et que nous devrions initialiser toutes nos variables,
nos pointeurs vers null.
Nous devrions donc toujours faire quelque chose comme ça.
Null est un symbole spécial en c qui représente le pointeur équivalent à
zéro avec des nombres ordinaires.
Ce qui suit définit également un pointeur sur null en utilisant zéro.
Donc, nous pouvons aussi si nous ne voulons pas le passer ou l'assigner à null, nous pouvons simplement
dire 0 et c'est l'équivalent de ne pointer vers rien.
Donc, comme null est l'équivalent de 0, si
vous voulez tester si la valeur p est nulle, vous pouvez faire quelque chose
comme utiliser des tests explicites. Vous pouvez dire que le pointeur est égal à null.
Et si le pointeur est égal à null, ce qui signifie qu'il
est zéro, alors vous pouvez réellement faire quelque chose.
Donc, si ce n'est pas zéro ou non nul, c'est une valeur vraie ou
une autre valeur, c'est un moyen de vérifier les plantages.
Assurez-vous avant d'essayer de déréférencer quelque chose,
cela vous dira si la mémoire est allouée ou non.
Vous voulez donc vérifier la valeur null avant de déréférencer un pointeur.
Et vous faites souvent cela dans les fonctions
parce que les fonctions prendront des pointeurs comme paramètres.
Et si l'appelant passe
des données incorrectes ou passe un pointeur n'a pas de mémoire allouée,
il peut planter votre code. Donc, ce que vous voulez faire, c'est vous
assurer que l'appelant a une adresse valide afin que vous puissiez la vérifier pour null.
Fondamentalement, ce que cela signifie de toujours les avoir si vérifie de
dire pas de valeur p ou pas de pointeur.
Et s'il ne s'agit pas d'un pointeur, vous pouvez le déréférencer.
Nous parlons beaucoup de pointeurs. Nous avons beaucoup discuté.
Je suis sûr que cela devient un peu écrasant. Vous voudrez peut-être faire une pause
et parcourir les conférences précédentes pour essayer de vraiment synchroniser ce concept dans votre tête.
Les pointeurs ne contiennent que des adresses.
Mais il y a 3 parties, donc cela peut devenir problématique.
Mais restez positif. Restez avec moi et je
sais que c'est déroutant.
Nous avons parlé de travailler avec des adresses.
Nous avons parlé de travailler avec des valeurs. Nous avons parlé de travailler avec le pointeur
lui-même, et nous avons parlé de travailler avec des variables qui pointent vers le pointeur.
Il y a donc toutes ces
choses dont vous devez vous souvenir, et cela peut être très accablant et frustrant.
Et il est toujours difficile d'essayer de comprendre ce qui se passe et cela va demander beaucoup de pratique.
La meilleure façon de comprendre ce concept et tout ce dont nous avons discuté
jusqu'à présent est de pratiquer,
d'écrire des programmes courts qui utilisent tous les concepts que j'ai mentionnés.
Donc, écrivez un programme qui obtient les
valeurs à l'aide d'un pointeur, ce serait peut-être en utilisant
l'opérateur d'indirection, le déréférencement. Écrivez un programme qui change les valeurs à l'aide de pointeurs.
Donc, ce serait déréférencer, obtenir les valeurs à l'aide de pointeurs ne serait
que le nom du pointeur qui serait l'adresse. Impression d'adresses, nous avons parcouru toute cette syntaxe.
Pratiquez ce truc encore et encore et encore et encore, c'est comme ça que vous allez devenir bon.
Il faut prendre confiance en soi et étudier ces concepts en
détail pour les maîtriser.
Nous avons encore beaucoup à dire sur les pointeurs, mais le moment est peut-être venu de prendre du recul et de revenir
sur ce dont nous avons parlé jusqu'à présent afin que cela vous soit ancré dans la tête.
Merci.