Récemment, j'ai essayé d'expliquer les pointeurs de manière visuelle, sous forme de cartes mémoire.
Question 001: Ceci est le dessin d'un emplacement dans la mémoire de l'ordinateur. Est-il vrai que son adresse est
0x23452
? Pourquoi?Réponse: Oui, car
0x23452
décrit où l’ordinateur peut trouver cet emplacement.
Question 002: Est-il vrai que le caractère
b
est stocké dans l'emplacement de mémoire0x23452
? Pourquoi?Réponse: Non, car le personnage
a
est réellement stocké à l'intérieur.
Question 003: Est-il vrai qu'un pointeur est stocké dans l'emplacement de mémoire
0x23452
? Pourquoi?Réponse: Oui, parce que l'adresse de l'emplacement de la mémoire
0x34501
est stockée à l'intérieur.
Question 004: Est-il vrai qu'un pointeur est stocké dans l'emplacement de mémoire
0x23452
? Pourquoi?Réponse: Oui, parce que l'adresse d'un autre emplacement de mémoire est stockée à l'intérieur.
Maintenant pour la partie qui m'a inquiété. Un ingénieur en logiciel m'a expliqué les pointeurs comme ceci:
Un pointeur est une variable dont la valeur est l'adresse mémoire d'une autre variable.
Sur la base des quatre cartes mémoire que je vous ai montrées à tous, je définirais les pointeurs d'une manière légèrement différente:
Un pointeur est un emplacement de mémoire dont la valeur est l'adresse de la mémoire d'un autre emplacement de mémoire.
Est-il prudent de dire qu'une variable est la même chose qu'un emplacement de mémoire?
Si non, alors qui a raison? Quelle est la différence entre une variable et un emplacement de mémoire?
a
,0x23453
.nil
etc. les choses à l'intérieur sont les valeurs. Cela peut sembler évident pour vous, mais je ne serais pas à l'aise de donner des réponses décisives à ces questions sans voir comment ces domaines sont définis. Il n'y a vraiment aucun moyen de savoir sia
dans la seconde image est un caractère, une chaîne (si elles sont différentes) ou le nom d'une variable. Si c'est une chaîne, alors c'estnil
aussi une chaîne? Ou une valeur "nulle"?Réponses:
Une variable est une construction logique qui correspond à l'intention d'un algorithme, tandis qu'un emplacement mémoire est une construction physique qui décrit le fonctionnement d'un ordinateur. De manière générale, pour exécuter un programme, il existe un mappage (généré par le compilateur) entre la notion logique de variable et le stockage de l'ordinateur.
(Même en langage assembleur, nous avons une notion de variables (logiques) allant à l'algorithme et à l'intention, ainsi que des emplacements mémoire (physiques), bien qu'ils soient plus regroupés dans l'assembly.)
Une variable est un concept de niveau élevé (er). Une variable représente soit un inconnu (comme en mathématiques ou une tâche de programmation), soit un paramètre fictif pouvant être remplacé par une valeur (comme dans la programmation: paramètres).
Un emplacement de mémoire est un concept de bas niveau. Un emplacement de mémoire peut être utilisé pour stocker une valeur, parfois pour stocker la valeur d'une variable. Cependant, un registre de CPU est un autre moyen de stocker la valeur de certaines variables. Les registres de la CPU sont également des emplacements de stockage de bas niveau, mais ils ne sont pas des emplacements de mémoire car ils ne possèdent pas d’adresses, mais juste des noms.
Dans un certain sens, une variable est un mécanisme d'abstraction permettant d'exprimer l'intention du programme, tandis qu'un emplacement mémoire est une entité physique de l'environnement de traitement qui fournit le stockage et la récupération.
Nous ne pouvons pas dire d'avance. Ce n’est pas parce qu’il existe une valeur qui fonctionnerait comme une adresse que cela pourrait être l’adresse, il pourrait s’agir de l’entier (décimal) 144466. Nous ne pouvons pas émettre d'hypothèses sur l'interprétation des valeurs simplement en fonction de la façon dont elles apparaissent numériquement.
C'est en effet une question étrange. Ils s'attendent à des hypothèses basées sur les cases, cependant, notons que les adresses augmentent de 1 pour chaque case. Sur n'importe quel ordinateur moderne, cela signifierait que chaque boîte peut contenir un adressage sur un octet, qui est la norme depuis des décennies. Cependant, un octet ne contient que 8 bits et peut aller de 0 à 255 (pour les valeurs non signées); pourtant, ils affichent une valeur beaucoup plus grande stockée dans l'une de ces adresses, donc très suspecte. (Cela pourrait fonctionner s'il s'agissait d'une machine adressée à un mot, mais ce n'est pas ce qui est dit et, aujourd'hui, peu de machines le sont, bien que certaines machines éducatives le soient aussi.)
Bien qu'il existe des situations où cette pensée est correcte, vous mélangez des métaphores ici. La notion de variable concerne l’algorithme et son objectif - il n’est pas nécessaire de supposer que toutes les variables ont des emplacements de mémoire. Certaines variables (notamment les tableaux) ont des emplacements de mémoire car ceux-ci prennent en charge l’adressage (alors que les registres de CPU ne peuvent être nommés que non indexés).
Pour l'exécution, il existe un mappage logique entre les variables et les instructions, les emplacements mémoire du processeur et les séquences d'instructions du processeur. Une variable dont la valeur ne change jamais (par exemple une constante) ne nécessite même pas nécessairement un emplacement de mémoire, car la valeur peut être reproduite à volonté (par exemple si nécessaire pour les séquences de code générées par le compilateur).
la source
for
index de boucle lorsque le compilateur décide de dérouler complètement la boucle. Nulle part dans le code de sortie produit (qu'il s'agisse d'un code d'assemblage, d'un code machine ou d'un code d'octet), il n'y a un emplacement de mémoire dans lequel le compteur de boucles est stocké. Mais c'est toujours une variable.source
dans un tableau de longueur égale,dest
une boucle codéefor (int i=0; i<8; ++i) dest[i] = source[i];
pourrait bien être compilée jusqu'à obtenir quelque chose d'équivalent à la répétition dudest++ = source++;
nombre de fois approprié. Avec le compteur de boucles lui-même n’est nulle part en évidence (pas même dans le registre), et seul le nombre de répétitions vous renseigne sur la condition de la boucle.La variable et l'emplacement mémoire sont deux abstractions à deux niveaux d'abstraction différents. Les variables et les pointeurs sont un concept de niveau supérieur au niveau du code / langue, la mémoire est un concept de niveau inférieur au niveau de la machine. Une fois qu'un code a été compilé dans un exécutable, il n'y a plus aucune variable. Essayer de parler de l'emplacement de la mémoire et des variables de cette manière est une erreur catégorique.
Une variable peut être implémentée en utilisant la mémoire, mais pas toujours comme un compilateur peut optimiser un calcul et faire tous les calculs relatifs à une variable entièrement dans des registres, ou il peut mettre une seule variable dans plusieurs emplacements de mémoire, ou utiliser une seule mémoire. emplacement pour plusieurs variables.
Cette série de cartes mémoire est tellement confuse qu’elles ne sont pas simplement mauvaises, mais elles ne sont même pas mauvaises.
la source
Once a code had been compiled into an executable, there's no longer any variables.
C'est quelque chose avec lequel je suis en désaccord. Il est exact que votre variable telle que vous la connaissez (c'est-à-dire sous ce nom) n'existe plus, mais votre phrasé semble suggérer que l'exécutable compilé utilise uniquement des adresses de mémoire. Ce n'est pas correct Votre exécutable compilé mais non exécutable n'a aucune idée des adresses de mémoire qu'il utilisera lors de son exécution. Le concept de variable (c'est-à-dire une référence réutilisable à l'adresse de mémoire affectée au moment de l'exécution) existe toujours à l'intérieur de l'exécutable compilé.Les variables sont des constructions de langage . Ils ont un nom, résident dans une portée, peuvent être référencés par d'autres parties du code, etc. Ils constituent une entité logique . Le compilateur est libre d'implémenter cette construction de langage comme bon lui semble, à condition que le comportement observable soit celui prescrit par le standard de langage. En tant que telle, la variable n'a même pas besoin d'être stockée n'importe où si le compilateur peut prouver que cela n'est pas nécessaire.
Les emplacements de mémoire sont un concept matériel . Ils signifient une place dans la mémoire virtuelle / physique. Chaque emplacement de mémoire a exactement une adresse physique et une quantité d'adresses virtuelles pouvant être utilisées pour le manipuler. Mais il y a toujours exactement un octet stocké dans chaque emplacement de mémoire.
Les pointeurs sont un type particulier de valeurs . Dire quelque chose est un pointeur revient à dire que quelque chose est de type
double
. Cela signifie combien de bits sont utilisés pour la valeur et comment ces bits sont interprétés, mais cela ne signifie pas que cette valeur est stockée dans une variable, ni que cette valeur est stockée en mémoire.Pour donner un exemple en C: quand j’ai un tableau 2D
int foo[6][7];
et que j’accède à un élément de celui-ci avecfoo[1][2]
,foo
c’est une variable qui contient un tableau. Lorsquefoo
est utilisé dans ce contexte, il est transformé en un pointeur sur le premier élément du tableau. Ce pointeur n'est stocké dans aucune variable, ni en mémoire, sa valeur est uniquement générée dans un registre de la CPU, utilisé puis oublié. De même, l'expressionfoo[1]
est transformée en un autre pointeur dans ce contexte, qui, là encore, n'est pas dans une variable, n'est pas stocké en mémoire, mais calculé dans la CPU, utilisé et oublié. Les trois concepts de variable , l' emplacement de la mémoire et le pointeur sont en réalité trois concepts différents.Btw, je voulais vraiment dire "il y a toujours exactement un octet stocké à chaque emplacement de mémoire". Ce n'était pas le cas à l'âge de pierre de l'informatique il y a une cinquantaine d'années, mais c'est vrai pour pratiquement tout le matériel utilisé aujourd'hui. Chaque fois que vous stockez une valeur en mémoire supérieure à un octet, vous utilisez en réalité un certain nombre d'emplacements de mémoire consécutifs. C'est-à-dire (en supposant que l'ordre des octets big endian), le nombre 0x01234567 est stocké en mémoire
(Les petites machines comme l’architecture X86 stockent les octets dans l’ordre inverse.) Cela vaut également pour les pointeurs: un pointeur sur une machine 64 bits est stocké sur huit octets consécutifs, chacun avec sa propre adresse de mémoire. Vous ne pouvez pas regarder une cellule mémoire et dire: "Oh, c'est un pointeur!" Vous ne voyez toujours que des octets lorsque vous examinez la mémoire .
la source
Laissez-moi me concentrer sur votre question actuelle - "qui a raison?" en comparant ces deux affirmations:
La réponse à cette question est non . La première parle d'une "adresse mémoire d'une autre variable", mais les variables n'ont pas nécessairement d'adresses de mémoire, comme les autres réponses l'ont déjà expliqué. Le second indique "un pointeur est un emplacement de mémoire", mais un pointeur est littéralement un nombre, qui peut être stocké dans une variable, mais comme auparavant, une variable n'a pas nécessairement d'adresse de mémoire.
Quelques exemples d’énoncés plus précis:
"Un pointeur est un nombre représentant l'adresse de la mémoire d'un emplacement de mémoire", ou
"Une variable de pointeur est une variable dont la valeur est l'adresse de la mémoire d'un emplacement de mémoire."
"Une adresse mémoire peut contenir un pointeur représentant l’adresse mémoire d’un emplacement mémoire."
Notez parfois que le terme "pointeur" est utilisé comme raccourci pour "variable de pointeur", ce qui est correct tant qu'il ne crée pas de confusion.
la source
Je ne dirais certainement pas qu'un pointeur est un emplacement de mémoire contenant une adresse. D'une part, je ne suis pas au courant d'une architecture où
0x23453
un seul octet pourrait tenir. :) Même si vous supprimez la distinction octets / mots, vous avez toujours le problème que chaque emplacement de mémoire contient une adresse. Les adresses ne sont que des chiffres et le contenu de la mémoire ne sont que des chiffres.Je pense que le truc ici est que "le pointeur" décrit l'intention humaine , pas une caractéristique particulière de l'architecture. Cela ressemble à la façon dont un "caractère" ou une "chaîne" n'est pas une chose concrète que vous pouvez voir en mémoire - ce ne sont que des chiffres, mais ils fonctionnent comme des chaînes car ils sont traités de la sorte. "Pointeur" signifie simplement une valeur destinée à être utilisée comme adresse.
Honnêtement, si votre objectif est d’enseigner une langue particulière (Objective C?), Je ne suis pas sûr que tirer la cassette mémoire classique soit utile. Vous dites déjà des mensonges blancs en affichant des valeurs dactylographiées et des valeurs trop grandes pour un octet. Enseignez la sémantique et non la mécanique - la principale idée sur les pointeurs est qu'ils fournissent l' indirection , ce qui est un outil extrêmement utile à comprendre.
Je pense qu'une bonne comparaison pourrait être une URL, qui vous indique où trouver des données, mais pas les données elles-mêmes. Écoutez-moi:
Vous vous souciez rarement de ce que l'URL est réellement ; la grande majorité d'entre eux sont liés par des noms. Beaucoup de gens utilisent Internet sans savoir exactement comment une URL aboutit à une page; Certaines personnes sont complètement inconscientes des URL.
Toutes les chaînes ne constituent pas une URL ou ne sont pas destinées à être utilisées comme URL.
Si vous essayez de visiter une URL fictive ou une page qui existait auparavant mais qui a été supprimée depuis, vous obtenez une erreur.
Une URL peut pointer vers une image, du texte, de la musique ou un certain nombre d’autres éléments individuels, ou sur une page contenant divers éléments. Il est très courant d'avoir un tas de pages avec des dispositions similaires mais des données différentes.
Si vous créez une page Web et que vous souhaitez faire référence à des données figurant sur une autre page Web, vous n'avez pas besoin de tout copier / coller. vous pouvez simplement faire un lien vers elle.
N'importe quel nombre d'autres pages peut créer un lien vers la même URL.
Si vous avez une collection de pages similaires, vous pouvez créer une page d'index qui répertorie tous les liens, ou simplement un lien "Suivant" au bas de la page 1 qui vous mène à la page 2, etc. Les avantages et les inconvénients des deux approches sont immédiatement évidents, en particulier si vous envisagez ce que le webmaster doit faire pour ajouter ou supprimer des pages à différents endroits.
Cette analogie, il est clair très ce que les pointeurs sont pour , ce qui est essentiel pour les comprendre - sinon ils semblent arbitraires, compliqué et inutile. Comprendre comment quelque chose fonctionne est beaucoup plus facile si vous comprenez déjà ce que cela fait et pourquoi c'est utile. Si vous avez déjà compris qu'un pointeur est une boîte noire qui vous indique où quelque chose d' autre est, et puis vous en apprendre davantage sur les subtilités du modèle de mémoire, représentant alors des pointeurs comme des adresses est assez évidente. De plus, la sémantique de l'enseignement mettra vos étudiants dans un endroit bien meilleur pour comprendre et inventer d'autres formes d'indirection - ce qui est bien quand la plupart des langues principales n'ont pas de pointeur!
la source
every memory location contains an address
- Chaque emplacement de mémoire a une adresse. Ce n'est contenu nulle part, sauf peut-être dans une variable de pointeur.Je sais que vous avez déjà accepté une réponse, et cette question a déjà cinq réponses, mais il y a un point qu'ils ne mentionnent pas, un qui, je pense, vous a fait trébucher. Les manuels CS tentent souvent d’être agnostiques quant au choix du langage de programmation, ce qui laisse supposer implicitement que la terminologie utilisée pour décrire les choses est universelle. Ce n'est pas.
En C, l'opérateur unary esperluette s'appelle l'opérateur "address-of". Les programmeurs C n'hésiteraient pas à dire que l'expression est
&x
évaluée à l'adresse de la variable x. Bien sûr, ils signifient "l'adresse mémoire dans laquelle est stockée la valeur de la variable x", mais personne n'est aussi pédant dans une conversation informelle. En C, le mot "pointeur" fait généralement référence au type de données d'une variable destinée à avoir une adresse mémoire comme valeur. Ou équivalent le type de données de la valeur. Mais certaines personnes utiliseraient "pointeur" comme valeur elle-même.En Java, toutes les variables de type objet ou tableau se comportent beaucoup comme des pointeurs C (à l’exception de l’arithmétique de pointeur), mais les programmeurs Java les appellent des références et non des pointeurs.
C ++ considère que les références et les pointeurs sont des concepts différents. Ils sont liés, mais pas tout à fait la même chose, donc les programmeurs C ++ doivent faire la distinction dans la conversation. L'esperluette est lue comme "adresse-de" dans certains contextes et "référence-à" dans d'autres.
Voilà comment un programmeur C pourrait le décrire, en utilisant "un pointeur" dans le même sens que "un int." (Comme dans "un pointeur contient une adresse mémoire, alors qu'un int contient un entier compris dans une certaine plage".)
C'est une façon étrange de le dire, car cela nécessite une définition très vague et informelle de «est».
Il serait plus clair de dire qu'une adresse mémoire est l'emplacement dans la mémoire où la valeur d'une variable est stockée. (Accordée, toutes les variables ne sont pas stockées en mémoire, à cause des optimisations du compilateur, mais toutes les variables dont l'adresse est prise le
&x
seront.)la source
L'instruction Un pointeur est une variable dont la valeur est l'adresse mémoire d'une autre variable est simplifiée à l'excès. Mais au moment où un lecteur comprendra ce qu'est exactement un emplacement mémoire et comment il diffère d'une variable, il comprendra déjà ce qu'est exactement un pointeur et n'aura donc plus besoin de s'appuyer sur cette explication inexacte.
L'instruction Un pointeur est un emplacement mémoire dont la valeur est l'adresse de la mémoire d'un autre emplacement mémoire incorrect. Il n'est pas nécessaire que la valeur d'un pointeur soit stockée dans un emplacement de mémoire. Si un pointeur doit pointer sur un emplacement de mémoire, cela peut faire l'objet d'un débat, en fonction de la définition souhaitée de "mémoire".
Un emplacement de mémoire est l'un des multiples emplacements possibles où les données peuvent être stockées. Ces données peuvent être une variable ou une partie d’une variable. Les variables sont un moyen d'étiquetage des données.
la source
Cette réponse se concentre sur C et C ++; cela semble approprié puisque votre question concerne les pointeurs qui font plus partie intégrante de C / C ++ que d’autres langages. La plupart de cet article s'appliquera à la plupart des langages compilés sans une exécution complexe (comme Pascal ou Ada, mais pas comme Java ou C #).
Les bonnes réponses déjà données soulignent qu'une variable est une construction de langage à un niveau plus abstrait que la mémoire physique. Je voudrais cependant souligner que cette abstraction a une certaine logique et un certain système:
L'abstraction consiste principalement à utiliser un nom au lieu d'une adresse littérale.
L'idée principale est qu'une variable est un handle nommé pour un objet typé; les objets en C / C ++ sont généralement en mémoire. Les langues ajoutent ensuite quelques détails concernant la gestion de la durée de vie et le marshaling des données pour les conversions de types. Le concept de variable est plus abstrait que les adresses physiques, car nous ne nous soucions pas de la valeur numérique des adresses ni de l'emplacement exact des fonctions en mémoire. Nous les nommons simplement et nous les adressons ensuite par leur nom, et le compilateur, l’éditeur de liens et le système d’exécution s’occupent des détails.
Et ne prétendez pas que C / C ++ n’est pas agnostique en mémoire: il existe, après tout, l’opérateur d’adresse universellement applicable. Oui, vous ne pouvez pas prendre l'adresse d'une variable C dans la classe de stockage de registre; mais quand en as-tu utilisé un dernier? Il s’agit d’une exception spéciale au concept général et non d’un rejet complet de l’argument. La règle générale est au contraire que prendre une adresse de variable oblige en fait le compilateur à créer un objet en mémoire, même s'il ne le ferait pas autrement (par exemple avec des constantes). Le concept de "poignée nommée" est également un bon paradigme pour les références C ++: une référence est simplement un autre nom du même objet.
Quand j’ai écrit inline assembler pour 68k, c’était bien de voir comment utiliser les noms de variables comme décalages pour les registres d’adresses (et les noms de variables déclarées à la
register
place des noms de registres à nu!). Pour le compilateur, une variable est un décalage d'adresse constant. Pour réitérer: Les variables sont des descripteurs nommés, généralement des objets en mémoire.la source
On dirait que la question s'adresse à un langage populaire formé en augmentant la norme C avec la garantie supplémentaire "Dans les cas où certaines parties de la norme ou la documentation d'une implémentation décrivent le comportement de certaines actions, et d'autres les catégorisent comme non définies , la première partie domine. ", ainsi qu’une définition de" variable "cohérente avec l’utilisation du terme dans d’autres langues.
Dans cette langue, chaque emplacement de mémoire peut être considéré comme une boîte aux lettres numérotée contenant toujours un certain nombre (généralement huit) de bits, chacun pouvant être indépendamment zéro ou un. Les emplacements de mémoire sont généralement organisés en rangées de deux, quatre ou huit. et certaines opérations traitent simultanément sur plusieurs emplacements de mémoire. En fonction de la machine, certaines opérations opérant sur des groupes de deux, quatre ou huit emplacements de mémoire peuvent être limitées à des emplacements situés sur une seule ligne. En outre, alors que certaines machines peuvent avoir une seule pièce de boîtes aux lettres numérotées consécutivement, d’autres peuvent avoir plusieurs groupes de boîtes aux lettres numérotées et disjointes.
Une variable identifie une plage d'emplacements de mémoire qui lui sont associés exclusivement et un type en tant que ces emplacements de mémoire doivent être interprétés. La lecture d'une variable entraîne l'interprétation des bits situés dans ses emplacements de stockage associés d'une manière appropriée au type de la variable, et l'écriture d'une variable entraîne la définition des bits associés d'une manière appropriée à son type et à sa valeur.
Une adresse encapsule toutes les informations nécessaires pour identifier une boîte aux lettres. Cela peut être stocké sous la forme d'un numéro simple ou d'une sorte d'indicateur de groupe avec le numéro d'une boîte aux lettres de ce groupe.
L'application de l'
&
opérateur à une variable produira un pointeur qui encapsule l'adresse et le type de celle-ci. L’application du unaire*
ou de l’[]
opérateur à un pointeur entraîne l’interprétation ou la définition des bits des boîtes aux lettres commençant à une adresse encapsulée, d’une manière appropriée au type encapsulé.la source
J'arrive en retard à cette soirée mais je ne peux pas m'empêcher de mettre mes 2 centimes dedans.
À ces moments, quelle est la différence entre les valeurs stockées dans ces emplacements de mémoire?
Temps 1
Temps 2
Bonne réponse: rien. Ce sont toutes des valeurs identiques présentées avec des interprétations différentes de leur signification.
Comment je sais ça? Parce que c'est moi qui ai inventé ça. Vous ne le savez pas vraiment encore.
Vous rencontrez quelque chose que j'appelle le problème hors bande . Comment interpréter correctement la signification de ces valeurs n'est pas stocké ici. Cette connaissance est stockée ailleurs. Pourtant, lorsque vous présentez ces valeurs sur papier, vous mettez cette interprétation. Cela signifie que vous avez ajouté des informations qui n'existent tout simplement pas dans ces emplacements de mémoire.
Par exemple, les valeurs ici sont identiques, mais vous savez que cela n’est vrai que si vous avez raison lorsque vous supposez qu’un encodage de caractères ASCII / UTF-8 correspond à la façon dont j’ai obtenu le premier, plutôt que de dire EBCDIC . Et vous devez également supposer que la deuxième expression est une expression hexadécimale des valeurs numériques stockées dans ces emplacements de mémoire, qui pourraient toutes être des pointeurs vers d'autres adresses, plutôt que de dire des références à des chaînes qui commencent toutes par "0x". : P
Rien stocké dans ces emplacements de mémoire ne vous dit que ces hypothèses sont correctes. Cette information peut être stockée. Mais il serait stocké ailleurs.
C'est le problème de présentation . Vous ne pouvez exprimer aucun chiffre sans d'abord vous mettre d'accord sur la manière de le présenter. Vous pouvez vous appuyer sur des hypothèses, des conventions et du contexte, mais si vous y réfléchissez profondément, lorsque la présentation n'est pas explicitement définie, la seule réponse vraiment correcte est "pas assez d'informations".
la source