Pointeur de pointeur de précisions
Je suivais ce tutoriel sur comment un pointeur vers un pointeur travail.
Permettez-moi de citer le passage pertinent:
int i = 5, j = 6, k = 7; int *ip1 = &i, *ip2 = &j;
Maintenant, nous pouvons définir
int **ipp = &ip1;
et
ipp
points deip1
qui points ài
.*ipp
estip1
, et**ipp
esti
, ou 5. On peut illustrer la situation, avec notre familier de la boîte-et-flèche de notation, comme ceci:Si nous pouvons alors dire
*ipp = ip2;
nous avons changé le pointeur pointé par
ipp
(qui est,ip1
) pour contenir une copie deip2
, de sorte qu'il (ip1
) maintenant les points àj
:
Ma question est: Pourquoi, dans la deuxième image, est ipp
pointe toujours vers le ip1
mais pas ip2
?
- s'il vous plaît, ajouter le type de
ipp
lors de la définition, de sorte que votre question est terminée 😉 - La manière dont vous avez doublé vos photos, la première ligne sont tous les objets de type
int
, la deuxième rangée sont tousint *
et de l'ipp estint **
. Quand vous dites*ipp = ip2;
de la lecture et de l'écriture que sur leint *
ligne de votre diagramme. - Savez-vous comment faire des liens symboliques de travail? Les pointeurs sont un peu comme les liens symboliques (que vous avez à déclarer, au moment de la compilation exactement combien de couches de pointeurs que vous pouvez avoir).
- Avez-vous dessinez les diagrammes à la main? Si non, quel outil utilisez-vous?
- Parce que
ipp
pointant versip1
donc*ipp = ip2
est la même queip1 = ip2
- Pouvons-nous arrêter d'écrire asteriks loin de la pointe type?
int **ipp
est beaucoup moins intuitive queint** ipp
, surtout quand**ipp
signifie une chose complètement différente à l'extérieur de déclarations de type. int **ipp
semble assez intuitif pour moi. Cela veut dire, je suis en train de faire**ipp
unint
. Ce qui est vrai.- Je n'ai jamais vu de cette façon. La pensée
ipp
est un pointeur vers un pointeur deint
(akaint**
) semble plus facile pour moi. - les significations et les personnels de l'intuitivité en dehors, pensez à ceci: Le type de
ipp
estint**
, de sorte il suffit d'écrireint**
au lieu de "magiqueimp
de déréférencement est un int" compréhensions. - Mais sur
int** a, b
, vous n'obtenez pas de deux pointeurs. Donc, ici, il est mieux écrit queint **a, b, *c, ***d
. (Non, ne pas l'écrire, c'est mal lisible. Mais si tu avais déjà serait dû à une quelconque raison, il serait prise en compte de cette façon.) - parce que vous ne modifiez pas la valeur de
ipp
Vous devez vous connecter pour publier un commentaire.
Oublier pendant une seconde à la pointe de l'analogie. Ce qu'est un pointeur contient en réalité est une adresse mémoire. Le
&
est l'adresse de l'exploitant - dire qu'elle renvoie l'adresse mémoire d'un objet. Le*
opérateur vous donne l'objet d'un pointeur désigne, c'est à dire un pointeur contenant une adresse, il renvoie l'objet à cette adresse mémoire. Ainsi, lorsque vous vous*ipp = ip2
, ce que vous faites est*ipp
obtenir l'objet à l'adresse deipp
qui estip1
et ensuite affecter àip1
la valeur stockée dansip2
, qui est l'adresse dej
.Simplement
&
--> Adresse de l'*
--> Valeur àParce que vous avez modifié la valeur pointée par
ipp
pas la valeur deipp
. Donc,ipp
encore des points àip1
(la valeur deipp
),ip1
's la valeur est maintenant le même queip2
's de la valeur, de sorte qu'ils pointent versj
.Ce:
est la même chose que:
int *ip1 = &i
et*ipp = ip2;
, c'est à dire si vous retirez leint
à partir de la première déclaration, les missions se ressemblent, mais la*
est en train de faire quelque chose de très différent dans les deux cas.espère que ce morceau de code peut vous aider.
il sorties:
Comme la plupart des questions de débutant dans le C balise, cette question peut être répondue par un retour aux principes de base:
&
opérateur transforme une variable dans un pointeur.*
opérateur transforme un pointeur sur une variable.(Techniquement, je devrais dire "lvalue" au lieu de "variable", mais je pense qu'il est plus facile à décrire mutable emplacements de stockage comme des "variables".)
Nous avons donc variables:
Variable
ip1
contient un pointeur. Le&
opérateur désactivei
en un pointeur et que la valeur du pointeur est attribué àip1
. Doncip1
contient un pointeur versi
.Variable
ip2
contient un pointeur. Le&
opérateur désactivej
en un pointeur et que le pointeur est attribué àip2
. Doncip2
contient un pointeur versj
.Variable
ipp
contient un pointeur. Le&
opérateur désactive variableip1
en un pointeur et que la valeur du pointeur est attribué àipp
. Doncipp
contient un pointeur versip1
.Résumons l'histoire:
i
contient 5j
contient 6ip1
contient "pointeur versi
"ip2
contient "pointeur versj
"ipp
contient "pointeur versip1
"Maintenant nous dire
La
*
opérateur transforme un pointeur de retour dans une variable. On va chercher la valeur deipp
, qui est "pointeur versip1
et de le transformer en une variable. Quelle variable?ip1
bien sûr!Donc c'est simplement une autre façon de dire
Nous avons donc aller chercher la valeur de
ip2
. Quel est-il? "pointeur versj
". Nous affecter que la valeur du pointeur deip1
, doncip1
est maintenant "pointeur versj
"Nous avons seulement changé une chose: la valeur de
ip1
:i
contient 5j
contient 6ip1
contient "pointeur versj
"ip2
contient "pointeur versj
"ipp
contient "pointeur versip1
"Une modification de la variable lorsque vous affectez à elle. Compter les devoirs; il ne peut y avoir plus de changements de variables qu'il y a des missions! Vous commencez par l'affectation à
i
,j
,ip1
,ip2
etipp
. Vous pouvez ensuite affecter à*ipp
, qui, comme nous l'avons vu, signifie la même chose que "attribuer àip1
". Puisque vous n'avez pas céder àipp
un deuxième temps, il n'a pas changé!Si vous vouliez changer
ipp
, alors vous aurez à attribuer àipp
:par exemple.
Mon opinion personnelle est que les photos avec des flèches pointant de cette façon, ou qui font des pointeurs plus difficile à comprendre. Il les rend semblent comme abstraite, des entités mystérieuses. Ils ne le sont pas.
Comme tout le reste dans votre ordinateur, les pointeurs sont numéros de. Le nom de "pointeur" est juste une façon élégante de dire "une variable contenant une adresse".
Par conséquent, permettez-moi de remuer les choses autour de en expliquant comment un ordinateur fonctionne réellement.
Nous avons une
int
, il a le nom dei
et la valeur 5. C'est stockée dans la mémoire. Comme tout ce qui est stocké dans la mémoire, il a besoin d'une adresse, ou nous ne serions pas en mesure de le trouver. Disonsi
se termine à l'adresse 0x12345678 et son copainj
avec la valeur 6 se termine juste après. En supposant un PROCESSEUR 32 bits où l'int est de 4 octets, et les pointeurs sont de 4 octets, alors les variables sont stockées dans la mémoire physique comme ceci:Maintenant, nous voulons souligner à ces variables. Nous avons créer un pointeur de type int,
int* ip1
, et unint* ip2
. Comme tout dans l'ordinateur, ces variables de pointeur obtenir alloué quelque part dans la mémoire trop. Supposons qu'ils finissent à la prochaine adjacentes adresses dans la mémoire, immédiatement aprèsj
. Nous avons mis les pointeurs pour contenir les adresses des variables précédemment alloué:ip1=&i;
("copier l'adresse de i dans ip1") etip2=&j
. Ce qui se passe entre les lignes est:Donc ce que nous avons eu étaient juste encore quelques 4 octets morceaux de mémoire contenant des nombres. Il n'y a pas de mystique ou magique flèches de nulle part en vue.
En fait, juste en regardant un vidage de la mémoire, nous ne pouvons pas dire si l'adresse 0x12345680 contient un
int
ouint*
. La différence est la façon dont notre programme choisit d'utiliser le contenu stockée à cette adresse. (La tâche de notre programme est en fait juste de dire à la CPU de quoi faire avec ces chiffres.)Ensuite, nous ajoutons encore un autre niveau d'indirection avec
int** ipp = &ip1;
. De nouveau, nous venons de passer une partie de la mémoire:Le modèle ne semblent familiers. Encore un autre bloc de 4 octets contenant un nombre.
Maintenant, si nous avions un vidage de la mémoire de la ci-dessus fictif peu de RAM, nous avons pu vérifier manuellement où ces pointeurs point. Nous coup d'oeil à ce qui est stocké à l'adresse de la
ipp
variable et de trouver le contenu 0x12345680. Ce qui est bien sûr l'adresse oùip1
est stocké. Nous pouvons aller à cette adresse, vérifiez le contenu de là, et de trouver l'adresse dei
, et puis, enfin, nous pouvons aller à cette adresse et de trouver le nombre 5.Donc, si nous prenons le contenu de l'ipp,
*ipp
, nous allons obtenir l'adresse du pointeur de variableip1
. En écrivant*ipp=ip2
nous copier ip2 en ip1, il est équivalent àip1=ip2
. Dans les deux cas, nous aurions(Ces exemples ont été donnés pour un big endian CPU)
location, value, variable
emplacement où a été1,2,3,4,5
et la valeur a étéA,1,B,C,3
, l'idée de pointeurs pourrait être expliqué facilement sans l'utilisation de flèches, qui sont intrinsèquement source de confusion. Avec tout ce que la mise en œuvre d'un choix, d'une valeur existe à un certain endroit, et c'est la pièce du puzzle qui devient brouillée lors de la modélisation avec des flèches.&
opérateur sur une variable vous donne une pièce de monnaie, qui représente cette variable. Le*
opérateur sur cette pièce permet la variable. Pas de flèches nécessaire!Avis les missions:
résultats
ipp
à point àip1
.donc pour
ipp
à point àip2
, nous devrions changer de la même manière,qui nous sont clairement pas en faire. Au lieu de cela, nous voulons changer le de la valeur à l'adresse pointé par
ipp
.En faisant ce qui suit
nous sommes juste en remplaçant la valeur stockée dans
ip1
.ipp = &ip1
, signifie*ipp = ip1 = &i
,Maintenant,
*ipp = ip2 = &j
.Donc,
*ipp = ip2
est essentiellement la même queip1 = ip2
.Pas plus tard cession a changé la valeur de
ipp
. C'est pourquoi il encore des points àip1
.Ce que vous faites avec
*ipp
, c'est à dire, avecip1
, ne change pas le fait queipp
points deip1
.vous mis de belles photos, je vais essayer de faire de belles ascii art:
Comme @Robert-S-Barnes a dit dans sa réponse: oublier les pointeurs, et quels sont les points à quoi, mais à penser en termes de mémoire. Fondamentalement, un
int*
signifie qu'il contient l'adresse d'une variable et d'uneint**
contient l'adresse d'une variable qui contient l'adresse d'une variable. Ensuite, vous pouvez utiliser le pointeur de l'algèbre pour accéder aux valeurs ou aux adresses:&foo
signifieaddress of foo
, et*foo
signifievalue of the address contained in foo
.Donc, comme des pointeurs est à propos de la gestion de la mémoire, de la meilleure façon de faire en sorte que "tangible" est de montrer ce que les pointeurs de l'algèbre à la mémoire.
Alors, voici votre programme en mémoire (simplifié pour les fins de l'exemple):
lorsque vous effectuez votre premier code:
voici comment votre mémoire ressemble à:
là, vous pouvez voir
ip1
etip2
obtient les adresses dei
etj
etipp
encore n'existe pas.N'oubliez pas que les adresses sont simplement des entiers stockés avec un type spécial.
Vous déclarer et défini
ipp
tels que:alors, voici votre mémoire:
et puis, vous êtes à la modification de la valeur pointée par l'adresse stockée dans
ipp
, qui estl'adresse stockée dans
ip1
:la mémoire du programme est
N. B.: comme
int*
est un type spécial, je préfère toujours éviter de déclarer plusieurs pointeurs sur la même ligne, je pense que leint *x;
ouint *x, *y;
notation peut être trompeuse. Je préfère écrireint* x; int* y;
HTH
ip2
devrait être3
pas4
.Parce que quand vous dites
vous êtes en train de dire l '"objet pointé par
ipp
" pour montrer la direction de la mémoire,ip2
pointe.Vous ne dites pas
ipp
à pointip2
.Si vous ajoutez l'opérateur de déréférencement
*
le pointeur, vous rediriger à partir du pointeur de la pointe-de objet.Exemples:
Donc:
Si vous voulez
ipp
à point àip2
, vous auriez à direipp = &ip2;
. Cependant, cela laisseraitip1
pointe toujours vers lei
.Début du jeu,
Maintenant déréférencement d'elle comme,
Considère chaque variable représentée comme ceci:
si vos variables devraient être représentés comme ceci
Que la valeur de
ipp
est&ip1
de sorte que le inctruction:les changements de la valeur à répondre à
&ip1
à la valeur deip2
, ce qui signifieip1
est modifié:Mais
ipp
encore:De sorte que la valeur de
ipp
encore&ip1
ce qui signifie qu'il pointe toujours àip1
.Car vous passez le pointeur de
*ipp
. Cela signifieipp
(varaiable nom)----aller à l'intérieur.ipp
est l'adresse deip1
.*ipp
donc aller à (adresse de l'intérieur)ip1
.Nous sommes maintenant au
ip1
.*ipp
(c'est à direip1
) =ip
2.ip2
contenant l'adresse dej
.doncip1
contenu sera remplacer par contenir des ip2(c'est à dire l'adresse de j),NOUS NE SOMMES PAS CHANGER
ipp
DE CONTENU.C'EST TOUT.
*ipp = ip2;
implique:Attribuer
ip2
à la variable pointée paripp
. C'est donc équivalente à:Si vous voulez l'adresse de
ip2
être stockés dansipp
, il suffit de faire:Maintenant
ipp
points deip2
.ipp
peut contenir une valeur de (j'.e point) un pointeur de pointeur type d'objet. Lorsque vous nepuis le
ipp
contient les adresse de la variable (pointeur)ip2
, qui est (&ip2
) de type pointeur de pointeur. Maintenant la flèche deipp
en deuxième pic va point àip2
.Wiki dit:
Le
*
opérateur est un opérateur de déréférencement fonctionne sur pointeur de variable, et renvoie un l-valeur (variable) équivalent à la valeur de l'adresse de pointeur. Ceci est appelé le déréférencement du pointeur.L'application de
*
opérateur suripp
derefrence à un l-valeur de pointeur versint
type. Le déréférencé l-valeur*ipp
est de type pointeur versint
, il peut contenir l'adresse d'uneint
type de données. Après la déclaration deipp
est tenue l'adresse deip1
et*ipp
est tenue l'adresse de (montrant)i
. Vous pouvez dire que*ipp
est un alias deip1
. Les deux**ipp
et*ip1
sont des alias pouri
.En faisant
*ipp
etip2
deux points au même endroit, maisipp
pointe toujours versip1
.Ce
*ipp = ip2;
n'est en fait qu'il copie le contenu deip2
(l'adresse dej
) àip1
(comme*ipp
est un alias pourip1
), pour effet de rendre les deux pointeursip1
etip2
pointant vers le même objet (j
).Ainsi, dans la seconde figure, flèche de
ip1
etip2
versj
toutipp
pointe toujours versip1
comme aucune modification n'est fait pour modifier la valeur deipp
.