Pointeurs
Motivation
Effets de bord
struct human {
int x;
int y;
int souffle;
};
void deplacerDroite(struct human a) {
a.x++;
a.souffle++;
}
struct human player;
void game_loop() {
...
if(isKeyRight())
deplacerDroite(player);
...
}
Que pensez-vous du programme ci-dessus ?
player n'est pas modifée quand on appuie sur la flèche de droite. Le contenu de player est copié quand on appelle deplacerDroite donc seul l'argument a, qui est une copie de player est modifié.
Structures de données
Pour l'instant, on connaît toujours la taille des valeurs de retour des fonctions, la taille des données manipulée. Donc sans pointeur :
- pas de tableau dynamique de taille variable
- pas d'arbres binaires de recherche
- pas de table de hachage
Solution : un pointeur
Un pointeur est une variable contenant une adresse mémoire.
void deplacerDroite(struct human *a) {
(*a).x++;
(*a).souffle++;
}
deplacerDroite(&player);
| Adresse | Données |
|---|---|
adresse | *adresse |
&data | data |
On a déjà vu cette solution pour les tableaux car on ne pouvait de toute façon pas faire autrement. Un tableau se dégrade en pointeur quand il est passé en argument :
void fillArray(int A[10]) {
...
}
est la même chose que
void fillArray(int A[]) {
...
}
qui est la même chose que
void fillArray(int *A) {
...
}
Exercice métaphorique
-
Si
xest une maison, qu'est ce que&x?L'adresse postale de x -
Si
xest un livre dans une bibliothèque, qu'est ce que&x?Sa côte qui donne sa localisation (pièce, étagère, etc.) -
Si
xest une page dans un livre, qu'est ce que&x?Le numéro de la page. -
Si
xest une variable déclaré parint x;, qu'est ce que&x?L'adresse mémoire où on trouve l'entier x.
-
Si
aest une adresse postale, qu'est ce que*a?La maison, le garage, l'hôpital, l'ENS, etc. qui se trouve à l'adresse a -
Si
aest la côte d'un livre dans une bibliothèque, qu'est ce que*a?Le livre en question dont la côte est a -
Si
aest une numéro de page d'un livre, qu'est ce que*a?Le contenu de la page numéro a -
Si
aest un pointeur sur un entier, déclaré parint *a;, qu'est ce que*a?*adésigne l'entier que l'on peut lire à l'adresse mémoirea.
Déclaration
Déclarer un entier
int a;
a est une variable contenant un entier.

Déclarer un pointeur sur un entier
int *p;
p est une variable contenant une adresse mémoire, à partir de laquelle on interprète le contenu comme un entier noté *p.

Combien de bits prend p en mémoire ?
Combien d'octets prend p en mémoire ?
Exercices
int x = 42;
int y;
y = x;
y++;
Que vaut x ? y = x réalise une affectation de la valeur de x dans y. C'est une copie. A la fin, y vaut 43 mais x vaut toujours 42.
int x = 42;
int *y;
y = &x;
(*y)++;
Que vaut x ? y = &x réalise une affectation de l'adresse de x dans y. A la fin, *y, qui n'est autre que x vaut 43. Bref, x vaut 43.
Placement de l'étoile
On peut écrire
int* p;
et
int *p;
Malheureusement, il vaut mieux écrire attacher l'étoile au nom de la variable. Par exemple :
int *p, i; // OUI
ou de manière équivalente
int* p, i; // NON car on pourrait croire que p et i sont de même type
déclare p comme un pointeur sur un int alors i est vraiment un int. Mieux encore, évitez les déclarations sur une seule ligne et écrivez :
int *p; // TRES CLAIR
int i; // TRES CLAIR
Typage
Toutes les variables suivantes sont des pointeurs :
int *p1;
float *p2;
struct point *p3;
...
Quelles est la taille de p1 ? de p2, de p3 ?

Il y aussi le type générique
void*
qui veut dire pointeur sur n'importe quoi.
void *p;
Cela veut dire pointeur vers n'importe quoi, et c'est à nous de savoir ce qu'il y a derrière. Le type void nous empêche d'interpréter les données pointées. Pour cela, on introduit une nouvelle variable :
void f(void *p)
{
int* pInt = p;
/*
j'utilise ici pInt qui est un pointeur sur un entier
*/
}
ou alors on caste :
void f(void *p)
{
int x = *((int*) p) + 1;
/*
j'utilise ici pInt qui est un pointeur sur un entier
*/
}
Scoop, quel est la taille d'un void* ?
Pointeur nul
Il y a une valeur particulière NULL (qui vaut 0). Elle signifie que le pointeur pointe sur rien. Le comportement normal d'un pointeur est implicitement d'un type optionel :
- soit il n'y a pas de données (et on pointe vers
NULL) - soit on pointe vers une donnée

Supposons que p est le pointeur nul, combien d'octets faut-il pour stocker p ?