Comment une adresse peut-elle avoir plusieurs valeurs?

int i[5]={0,1,2,3,4,}; int *ip=&i[0]; printf("%d,%d,%d,%d,%d,%d,%d,%d",*ip,ip,&ip,&i,&i[0],i,i[0],*(&i)); 

La sortie du code ci-dessus que j’ai eu dans ma composition est

 0,2358832,2358824,2358832,2358832,2358832,0,2358832 

Observez que les deux ip=&i=2358832 mais *ip=0 et *(&i)=2358832 . Comment une adresse, dans ce cas 2358832, peut-elle avoir deux valeurs?

Je vais essayer d’expliquer avec l’aide du diagramme.

 int i[5]={0,1,2,3,4,}; int *ip=&i[0]; 

Après ce code, nous avons deux variables: le tableau i de 5 int s et le pointeur ip qui pointe vers le premier élément du tableau i (c’est-à-dire qui contient l’adresse du premier élément du tableau i ). Voyons comment ces variables sont mises en mémoire (pour ce diagramme, je suppose qu’Ints a la taille 4 et les pointeurs 8, sur votre système, il peut être différent, mais pour votre question, cela n’a pas d’importance):

entrez la description de l'image ici

Voyons maintenant les arguments de printf et expliquons-les à l’aide du diagramme:

  • *ip – “Prenez la valeur de la variable ip2358832 – et interprétez cette valeur comme adresse, obtenez la valeur de type int (car ip a le type int * ) qui est stocké à cette adresse – 0 “;
  • ip – “Récupère la valeur de la variable ip2358832 “;
  • &ip – “Récupère l’adresse de la variable ip2358824 “;
  • &i – “Obtenir l’adresse de la variable i2358832 “;
    • Remarque 1: la variable occupe généralement plus d’une cellule de mémoire. Dans ce cas, “adresse de variable” désigne l’adresse de la première cellule de mémoire occupée par cette variable => la variable i occupe plusieurs cellules mais possède l’adresse “2358832” – l’adresse de sa première cellule;
    • Note 2: la variable ip occupe également plus d’une cellule (8 sur notre diagramme)
  • &i[0] – “Récupère l’adresse du premier élément du tableau i2358832 “;
  • i – “Récupère la valeur de la variable i? “. Celui-ci est délicat. Lorsque le compilateur demande d’obtenir “la valeur du tableau”, le compilateur obtient l’adresse du premier élément de ce tableau. Habituellement, cela s’appelle “tableau décompose en pointeur” . Donc, dans notre cas, i => &i[0] => 2358832 (voir ci-dessus);
  • i[0] – “Récupère la valeur du premier élément du tableau i0 “;
  • *(&i) – deux étapes:
    • &i => 2358832 (voir ci-dessus). Notez que cette valeur intermédiaire (comme toute autre valeur!) A le type. Dans ce cas, le type est int (*)[5]pointeur vers tableau .
    • *(&i) – “Obtenir la valeur du tableau qui est stocké à l’adresse 2358832 “. Comme nous le soaps déjà, “valeur de tableau” désigne l’adresse du premier élément de ce tableau – 2358832 .
 int i[5]={0,1,2,3,4,}; int *ip=&i[0]; printf("%d,%d,%d,%d,%d,%d,%d,%d",*ip,ip,&ip,&i,&i[0],i,i[0],*(&i)); 

Tout d’abord, c’est une erreur de formater une adresse avec %d . Utilisez %p pour cela. Vous vous en sortez parce que vos adresses se trouvent être des entiers sur 4 octets, la même taille que le type int de votre plate-forme.

Passons en revue celui-ci à la fois:

  • *ip est identique à i[0] .
  • ip contient l’adresse du premier élément du tableau, qui est également l’adresse du tableau car le tableau commence par son premier élément.
  • &ip contient l’adresse de la variable ip .
  • &i contient l’adresse du tableau, la même adresse que celle conservée dans ip , voir ci-dessus.
  • &i[0] est à nouveau identique à ip .
  • i est le tableau, qui se décompose en un pointeur, a donc la même valeur lorsqu’il est traité comme une adresse comme ip , &i[0] .
  • i[0] sais bien ce que c’est.
  • *(&i) est identique à i , voir ci-dessus.

Qu’est-ce qui vous énerve, c’est qu’après

 int i[5]={0,1,2,3,4,}; int *ip=&i[0]; 

“les deux ip = & i = 2358832 mais * ip = 0 et * (& i) = 2358832. Comment une adresse, dans ce cas 2358832, peut-elle avoir deux valeurs?”.

Deux expressions donnent chacune une adresse avec la même valeur numérique. Comment peut-il y avoir différentes valeurs stockées à la même adresse, comme le prouve l’impression du résultat du déréférencement de ces mêmes adresses?

Si vous y réfléchissez, la réponse doit se trouver dans le type d’ip vs & i (et la vérification du type faible de printf). Cela est lié à l’une des subtilités du système de type C / C ++ (hi Lundin). Souvent, un tableau “se décompose”, comme dit le jargon, en un pointeur sur son premier élément. C’est pourquoi vous pouvez passer i à une fonction prenant un pointeur (par exemple, printf), ou lui append 1 et obtenir l’adresse du prochain élément, ou simplement le déréférencer comme * i.

Prendre l’adresse d’un tableau est l’un des cas où il ne se détériore pas. Cela rest un tableau; & i a le type “pointeur sur tableau”, pas “pointeur sur int”. Le tableau partage son adresse avec son premier élément, les valeurs numériques sont donc identiques. Mais ce que le compilateur fait avec le pointeur est différent:

Dereferencing & i vous redonne le tableau, comme avec tout autre type; et que se passe-t-il lorsque vous transmettez cela à une fonction telle que printf? Enfin, il se décompose en un pointeur sur son premier élément, qui se trouve être à l’adresse bien connue 2358832.

Cela peut devenir plus clair si vous imaginez une structure à la place du tableau; les deux sont liés (une structure est également une série d’objects, uniquement de types différents). Un pointeur sur le premier membre de la structure a sûrement une signification différente de celle d’un pointeur sur la structure, bien qu’ils aient également la même valeur numérique.

Ou prenez le petit programme suivant (comportement ssortingctement parlé et non défini) qui indique qu’une même adresse peut porter “des valeurs différentes”, selon ce que vous indiquez au compilateur de faire avec les données qu’il contient:

 #include int main() { unsigned int sixpointo = 1086324736; float *fp = (float *)&sixpointo; printf("&sixpointo: %p, fp: %p, sixpointo: %d, *fp: %f\n", &sixpointo, fp, sixpointo, *fp); return 0; }