Veuillez inclure un exemple avec l'explication.
c++
c
pointers
dereference
asir
la source
la source
int *p;
définirait un pointeur sur un entier et*p
déréférencerait ce pointeur, ce qui signifie qu'il récupérerait en fait les données vers lesquelles p pointe.Réponses:
Révision de la terminologie de base
Il est généralement suffisant - sauf si vous programmez l'assembly - d'envisager un pointeur contenant une adresse mémoire numérique, 1 faisant référence au deuxième octet dans la mémoire du processus, 2 le troisième, 3 le quatrième et ainsi de suite ...
Lorsque vous souhaitez accéder aux données / valeurs dans la mémoire vers lesquelles pointe le pointeur - le contenu de l'adresse avec cet index numérique - vous déréférencer le pointeur.
Différents langages informatiques ont des notations différentes pour indiquer au compilateur ou à l'interpréteur que vous êtes maintenant intéressé par la valeur (actuelle) de l'objet pointé - je me concentre ci-dessous sur C et C ++.
Un scénario de pointeur
Considérez en C, étant donné un pointeur comme
p
ci-dessous ...... quatre octets avec les valeurs numériques utilisées pour coder les lettres 'a', 'b', 'c', et un octet 0 pour indiquer la fin des données textuelles, sont stockés quelque part en mémoire et l'adresse numérique de celle-ci les données sont stockées dans
p
. De cette façon, C code le texte en mémoire est appelé ASCIIZ .Par exemple, si le littéral de chaîne se trouvait à l'adresse 0x1000 et
p
un pointeur 32 bits à 0x2000, le contenu de la mémoire serait:Notez qu'il n'y a pas de nom / identifiant variable pour adresse 0x1000, mais on peut se référer indirectement à la chaîne littérale à l' aide d' un pointeur contenant son adresse:
p
.Déréférencer le pointeur
Pour faire référence aux caractères
p
pointés, nous déréférençons enp
utilisant l'une de ces notations (encore une fois, pour C):Vous pouvez également déplacer des pointeurs à travers les données pointées, en les déréférençant au fur et à mesure:
Si vous avez des données sur lesquelles vous pouvez écrire, vous pouvez faire des choses comme ceci:
Ci-dessus, vous devez avoir su au moment de la compilation que vous auriez besoin d'une variable appelée
x
, et le code demande au compilateur d'arranger où elle doit être stockée, garantissant que l'adresse sera disponible via&x
.Déréférencement et accès à un membre de données de structure
En C, si vous avez une variable qui est un pointeur vers une structure avec des membres de données, vous pouvez accéder à ces membres à l'aide de l'
->
opérateur de déréférencement:Types de données multi-octets
Pour utiliser un pointeur, un programme informatique a également besoin de quelques informations sur le type de données qui est pointé - si ce type de données a besoin de plus d'un octet pour représenter, le pointeur pointe normalement vers l'octet le moins numéroté dans les données.
Donc, en regardant un exemple un peu plus complexe:
Pointeurs vers la mémoire allouée dynamiquement
Parfois, vous ne savez pas combien de mémoire vous aurez besoin jusqu'à ce que votre programme soit en cours d'exécution et voit quelles données y sont lancées ... alors vous pouvez allouer dynamiquement de la mémoire en utilisant
malloc
. Il est courant de stocker l'adresse dans un pointeur ...En C ++, l'allocation de mémoire se fait normalement avec l'
new
opérateur, et la désallocation avecdelete
:Voir également les pointeurs intelligents C ++ ci-dessous.
Perte et fuite d'adresses
Souvent, un pointeur peut être la seule indication de l'emplacement de certaines données ou tampons en mémoire. Si une utilisation continue de ces données / tampon est nécessaire, ou la possibilité d'appeler
free()
oudelete
d'éviter une fuite de mémoire, le programmeur doit alors opérer sur une copie du pointeur ...... ou orchestrez soigneusement l'inversion de tout changement ...
Pointeurs intelligents C ++
En C ++, il est recommandé d'utiliser des objets de pointeur intelligent pour stocker et gérer les pointeurs, en les désallouant automatiquement lorsque les destructeurs des pointeurs intelligents s'exécutent. Depuis C ++ 11, la bibliothèque standard en fournit deux,
unique_ptr
car lorsqu'il n'y a qu'un seul propriétaire pour un objet alloué ...... et
shared_ptr
pour l'actionnariat (en utilisant le comptage des références ) ...Pointeurs nuls
En C,
NULL
et0
- et en plus en C ++nullptr
- peut être utilisé pour indiquer qu'un pointeur ne contient pas actuellement l'adresse mémoire d'une variable, et ne doit pas être déréférencé ou utilisé dans l'arithmétique des pointeurs. Par exemple:En C et C ++, tout comme les types numériques intégrés ne sont pas nécessairement définis par défaut sur
0
, nibools
surfalse
, les pointeurs ne sont pas toujours définis surNULL
. Tous ceux-ci sont définis sur 0 / false / NULL lorsqu'ils sont desstatic
variables ou (C ++ uniquement) des variables membres directes ou indirectes d'objets statiques ou de leurs bases, ou subissent une initialisation nulle (par exemplenew T();
etnew T(x, y, z);
effectuent une initialisation nulle sur les membres de T, y compris les pointeurs, tandis quenew T;
ne fait pas).En outre, lorsque vous attribuez
0
,NULL
etnullptr
à un pointeur, les bits du pointeur ne sont pas nécessairement tous réinitialisés: le pointeur peut ne pas contenir "0" au niveau matériel, ou faire référence à l'adresse 0 dans votre espace d'adressage virtuel. Le compilateur est autorisé à stocker quelque chose d' autre si elle a des raisons, mais ce qu'il fait - si vous venez le long et comparer le pointeur0
,NULL
,nullptr
ou un autre pointeur qui a été attribué l' un de ceux, le travail doit de comparaison comme prévu. Donc, en dessous du code source au niveau du compilateur, "NULL" est potentiellement un peu "magique" dans les langages C et C ++ ...En savoir plus sur les adresses mémoire et pourquoi vous n'avez probablement pas besoin de savoir
Plus strictement, les pointeurs initialisés stockent un modèle binaire identifiant soit
NULL
une adresse mémoire (souvent virtuelle ).Le cas simple est celui où il s'agit d'un décalage numérique dans tout l'espace d'adressage virtuel du processus; dans des cas plus complexes, le pointeur peut être relatif à une zone de mémoire spécifique, que le processeur peut sélectionner en fonction des registres de "segment" du processeur ou d'une certaine manière de l'ID de segment codé dans la configuration binaire, et / ou en regardant à différents endroits en fonction de la instructions du code machine utilisant l'adresse.
Par exemple, un
int*
fichier correctement initialisé pour pointer vers uneint
variable peut - après avoir été converti enfloat*
- accéder à la mémoire dans la mémoire "GPU", bien distinct de la mémoire où se trouve laint
variable, puis une fois casté et utilisé comme pointeur de fonction, il peut pointer vers plus loin. une mémoire distincte contenant des opcodes de machine pour le programme (avec la valeur numérique duint*
pointeur effectivement aléatoire non valide dans ces autres régions de mémoire).Les langages de programmation 3GL comme C et C ++ ont tendance à masquer cette complexité, de sorte que:
Si le compilateur vous donne un pointeur sur une variable ou une fonction, vous pouvez le déréférencer librement (tant que la variable n'est pas détruite / désallouée entre-temps) et c'est le problème du compilateur si par exemple un registre de segment de CPU particulier doit être restauré à l'avance, ou instruction de code machine distincte utilisée
Si vous obtenez un pointeur vers un élément d'un tableau, vous pouvez utiliser l'arithmétique du pointeur pour vous déplacer n'importe où ailleurs dans le tableau, ou même pour former une adresse un-après-la fin du tableau qui est légale à comparer avec d'autres pointeurs vers des éléments dans le tableau (ou qui ont été déplacés de la même manière par l'arithmétique du pointeur vers la même valeur un après la fin); encore une fois en C et C ++, c'est au compilateur de s'assurer que cela "fonctionne juste"
Des fonctions spécifiques du système d'exploitation, par exemple le mappage de la mémoire partagée, peuvent vous fournir des pointeurs, et elles "fonctionneront" dans la plage d'adresses qui leur convient.
Les tentatives de déplacer des pointeurs légaux au-delà de ces limites, ou de convertir des nombres arbitraires en pointeurs, ou d'utiliser des pointeurs castés en types non liés, ont généralement un comportement non défini , donc devraient être évitées dans les bibliothèques et applications de niveau supérieur, mais le code pour les systèmes d'exploitation, les pilotes de périphériques, etc. . peut avoir besoin de s'appuyer sur un comportement non défini par la norme C ou C ++, qui est néanmoins bien défini par leur implémentation ou leur matériel spécifique.
la source
p[1]
et*(p + 1)
identique ? C'est-à-dire, génère- tp[1]
- il et*(p + 1)
génère- t- il les mêmes instructions?p
est juste 2000: si vous aviez un autre pointeur vers lui,p
il devrait stocker 2000 dans ses quatre ou huit octets. J'espère que cela pourra aider! À votre santé.u
contient un tableauarr
, gcc et clang reconnaîtront que la lvalueu.arr[i]
pourrait accéder au même stockage que les autres membres de l'union, mais ne reconnaîtront pas que lvalue*(u.arr+i)
pourrait le faire. Je ne sais pas si les auteurs de ces compilateurs pensent que ce dernier invoque UB, ou que le premier invoque UB, mais ils devraient quand même le traiter utilement, mais ils voient clairement les deux expressions comme différentes.Déréférencer un pointeur signifie obtenir la valeur qui est stockée dans l'emplacement de mémoire pointé par le pointeur. L'opérateur * est utilisé pour ce faire et est appelé l'opérateur de déréférencement.
la source
[]
déréférence également un pointeur (a[b]
est défini comme signifiant*(a + b)
).Un pointeur est une "référence" à une valeur. Un peu comme un numéro d'appel de bibliothèque est une référence à un livre. "Déréférencer" le numéro d'appel est physiquement en train de parcourir et de récupérer ce livre.
Si le livre n'est pas là, le bibliothécaire commence à crier, ferme la bibliothèque et deux personnes sont prêtes à enquêter sur la cause d'une personne qui va trouver un livre qui n'est pas là.
la source
En termes simples, le déréférencement signifie accéder à la valeur à partir d'un certain emplacement de mémoire vers lequel ce pointeur pointe.
la source
Code et explication de Pointer Basics :
la source
Je pense que toutes les réponses précédentes sont fausses, car elles déclarent que le déréférencement signifie accéder à la valeur réelle. Wikipédia donne plutôt la bonne définition: https://en.wikipedia.org/wiki/Dereference_operator
Cela dit, nous pouvons déréférencer le pointeur sans jamais accéder à la valeur vers laquelle il pointe. Par exemple:
Nous avons déréférencé le pointeur NULL sans accéder à sa valeur. Ou nous pourrions faire:
Encore une fois, déréférencer, mais jamais accéder à la valeur. Un tel code ne plantera PAS: le crash se produit lorsque vous accédez réellement aux données par un pointeur non valide. Cependant, malheureusement, selon la norme, déréférencer un pointeur non valide est un comportement indéfini (à quelques exceptions près), même si vous n'essayez pas de toucher les données réelles.
Donc, en bref: déréférencer le pointeur signifie lui appliquer l'opérateur de déréférence. Cet opérateur retourne juste une valeur l pour votre utilisation future.
la source
*p;
provoque un comportement indéfini. Bien que vous avez raison déréférencement n'a pas accès à la valeur en soi , le code*p;
ne l' accès à la valeur.