Lorsque l'on pense aux pointeurs, il est utile de dessiner des diagrammes . Un pointeur est une flèche qui pointe vers une adresse en mémoire, avec une étiquette indiquant le type de la valeur. L'adresse indique où chercher et le type indique ce qu'il faut prendre. Le moulage du pointeur modifie l'étiquette de la flèche, mais pas l'endroit où elle pointe.
d
en main
est un pointeur sur c
qui est du type char
. A char
est un octet de mémoire, de sorte que lorsque d
est déréférencé, vous obtenez la valeur de cet octet de mémoire. Dans le diagramme ci-dessous, chaque cellule représente un octet.
-+----+----+----+----+----+----+-
| | c | | | | |
-+----+----+----+----+----+----+-
^~~~
| char
d
Lorsque vous lancez d
à int*
vous dites que d
indique en réalité un int
valeur. Sur la plupart des systèmes actuels, un int
occupe 4 octets.
-+----+----+----+----+----+----+-
| | c | ? | ? | ? | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
(int*)d
Lorsque vous déréférencez (int*)d
vous obtenez une valeur déterminée à partir de ces quatre octets de mémoire. La valeur obtenue dépend de ce que contiennent ces cellules marquées ?
et sur la manière dont un int
est représenté dans la mémoire.
Un PC est little-endian ce qui signifie que la valeur d'un int
est calculé de cette manière (en supposant qu'il couvre 4 octets) : * ((int*)d) == c + ? * 2 + ? * 2¹ + ? * 2²
. Vous verrez donc que, bien que la valeur soit erronée, si vous l'imprimez en hexadécimal ( printf("%x\n", *n)
), les deux derniers chiffres seront toujours 35
(c'est la valeur du caractère '5'
).
D'autres systèmes sont big-endian et organisent les octets dans l'autre sens : * ((int*)d) == c * 2² + ? * 2¹ + ? * 2 + ?
. Sur ces systèmes, vous constaterez que la valeur est toujours commence con 35
lorsqu'il est imprimé en hexadécimal. Certains systèmes ont une taille de int
qui diffère de 4 octets. Quelques rares systèmes organisent int
de différentes manières, mais il est très peu probable que vous les rencontriez.
En fonction de votre compilateur et de votre système d'exploitation, vous pouvez constater que la valeur est différente à chaque fois que vous exécutez le programme, ou qu'elle est toujours la même mais qu'elle change lorsque vous apportez des modifications, même mineures, au code source.
Sur certains systèmes, un int
doit être stockée à une adresse multiple de 4 (ou 2, ou 8). C'est ce qu'on appelle un alignement exigence. Selon que l'adresse de c
est correctement aligné ou non, le programme peut se bloquer.
Contrairement à votre programme, voici ce qui se passe lorsque vous avez une int
et de prendre un pointeur sur cette valeur.
int x = 42;
int *p = &x;
-+----+----+----+----+----+----+-
| | x | |
-+----+----+----+----+----+----+-
^~~~~~~~~~~~~~~~~~~
| int
p
Le pointeur p
pointe vers un int
valeur. L'étiquette de la flèche décrit correctement le contenu de la cellule de mémoire, de sorte qu'il n'y a pas de surprise lors du déréférencement.