< Chaînes de caractères | TutoCFrench | Passer des arguments à un programme >
Notions :
*
et &
const int *p
et int * const p
La notion de pointeur a la réputation d'être difficile à comprendre et encore plus à maîtriser. Il s'agit en fait d'une notion extrèmement simple : un pointeur est une variable qui stocke pour valeur une adresse mémoire :
On déclare un pointeur d'un type donné en ajoutant le signe *
avant le nom du pointeur. Dans l'exemple ci-dessous, ptr
stocke l'adresse d'une donnée de type char
et ptr2
stocke l'adresse d'une donnée de type int
.
char *ptr; int* ptr2; /* possible aussi ! */
&
L'opérateur &
sert à récupérer l'adresse mémoire d'une variable.
Dans l'exemple ci-dessous, on affiche l'adresse mémoire d'une variable :
int var = 4; printf("L'adresse de 'var' est %p\n", &var);
Dans l'exemple ci-dessous, on récupère l'adresse mémoire d'une variable pour l'affecter à une variable de type pointeur :
int var = 4; int *ptr; /* declaration de ptr en tant que pointeur sur 'int' */ ptr = &var; /* 'ptr' pointe sur la variable 'var' */ printf("L'adresse de 'var' est %p\n", ptr);
Il est aussi possible de pointer sur l'élément d'un tableau :
int tab[5]; int *p; p = &tab[4]; /* ptr pointe sur le dernier element du tableau */
*
Un pointeur contient une adresse en mémoire, et grâce à l'opérateur *
, on peut accèder à la valeur contenue à cette adresse (soit pour la modifier, soit pour l'examiner) :
int var = 5; int *p; p = &var; printf("La valeur de 'var' est %d\n", *p);
L'exemple ci-dessous illustre comment on peut modifier le contenu d'une variable indirectement, par son pointeur :
int var = 5; int *p; p = &var; *p = 4; printf("La valeur de 'var' est %d\n", var);
Les pointeurs peuvent être incrémentés, décrémentés, additionnés ou soustraits. Dans ce cas, leur nouvelle valeur dépend de leur type. Incrémenter un pointeur de char
ajoute 1 à sa valeur. Incrémenter un pointeur de int
ajoute 2 ou 4 (cela dépend de l'architecture).
Cette arithmétique appliquée aux pointeurs est utile quand on manipule des tableaux. En incrémentant un pointeur sur un élément d'un tableau, on pointe sur l'élément suivant :
int tab[] = {18, 21, 33}; int *p; p = &tab[0]; printf("%d\n", *p); /* Affiche '18' */ p++; printf("%d\n", *p); /* Affiche '21' */
*
Pour reprendre l'exemple ci-dessus, on peut accèder aux éléments d'un tableau sans altèrer la valeur de p
, grâce à une autre écriture :
p = &tab[0]; printf("%d\n", *p); /* Affiche '18' */ printf("%d\n", *(p+1)); /* Affiche '21' */ printf("%d\n", *(p+2)); /* Affiche '33' */
[]
L'opérateur crochet s'applique aussi aux pointeurs. Il permet de faire comme si un pointeur était un tableau. Ceci permet de beaucoup simplifier les écritures :
p = &tab[0]; printf("%d\n", p[0]); /* Affiche '18' */ printf("%d\n", p[1]); /* Affiche '21' */ printf("%d\n", p[2]); /* Affiche '33' */
Nous avons vu qu'il est possible de récupèrer l'adresse mémoire d'un élément d'un tableau. Mais nous pouvons aller encore plus loin ! En effet, un nom de tableau utilisé dans une expression est converti en une adresse sur le début de ce tableau :
int tab[] = {18, 21, 33}; int *p; p = tab; /* equivalent a : "p = &tab[0]" */
Quand une chaîne littérale est utilisée dans une expression, elle est convertie en une adresse sur le début de la chaîne :
int *ptr = "abcd"; printf("%s\n", ptr);
Les pointeurs de type void *
sont utilisés pour pointer sur quelque chose dont on ne connais pas le type. Les seuls opérateurs autorisés avec les pointeurs génériques sont :
=
)
Les autres opérateurs sont interdits. Parmi eux :
*p
p+i
p-i
Nous avons déjà vu la notion de passage par valeur qui ne permet pas à une fonction de modifier la valeur d'une variable passée en argument.
Grâce aux pointeurs, nous pouvons créer des fonctions qui modifient directement une variable passée en argument ! On appelle cette notion le passage par adresse.
Par exemple, la fonction ci-dessous incrémente la variable dont l'adresse est passée en argument :
void incr(int *n) { *n = *n + 1; } int main() { int a = 3; incr(&a); /* 'a' est incrementee */ printf("%d\n", a); return 0; }
L'appel à la fonction incr()
fonctionne en plusieurs étapes :
incr()
prend en argument l'adresse de la variable a
(l'opérateur &
retourne son adresse)
a
est stockée dans la variable n
de la fonction incr()
*
permet d'accèder au contenu de la case mémoire pointée par n
. En l'occurence, ici, on incrémente cette valeur
main()
qui affiche la nouvelle valeur de a
Remarque : un tableau est toujours passé par adresse dans une fonction. Quand une fonction prend en argument un tableau, elle travaille toujours sur l'original !
int **p; /* pointeur sur un pointeur d'entier */ int *t[10]; /* tableau de 10 pointeurs sur des entiers */ int (*pt) [5]; /* pointeur sur un tableau de 5 entiers */ int *fonc(); /* fonction renvoyant un pointeur sur un entier */ int (*pfonc) (); /* pointeur sur une fonction retournant un entier */
#include <stdio.h> void echange(int *a, int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; } int main() { int a, b; printf("a> "); scanf("%d", &a); printf("b> "); scanf("%d", &b); printf("after...\n"); printf("a = %d\nb = %d\n", a, b); return 0; }
< Chaînes de caractères | TutoCFrench | Passer des arguments à un programme >