Les pointeurs sont indispensables pour écrire certaines fonctions. Cette fiche précise pourquoi, comment et quand déclarer un paramètre pointeur lorsqu'on écrit une fonction.
1. Rappel : mécanisme d'appel de fonction en C
Rappel - rule of thumb : le mécanisme d'appel de fonction en C repose TOUJOURS sur un passage par valeur.
Supposons qu'on veuille une fonction qui échange le contenu de deux variables entières passées en paramètres. Naïvement on pourrait écrire le code suivant. Mais détaillons ce qui se passe...
Le programme précédent ne fait donc pas ce qu'on veut : il n'échange pas les valeurs des variables...
Mais alors, comment faire pour qu'une fonction change la valeur d'une variable qu'on lui indique ? Eh bien : on a recours à un passage "par adresse", au moyen d'un paramètre pointeur.
2. Exemple de passage par adresse
Pour que notre fonction echanger(...)
puisse échanger les variables du main qu'on veut échanger,
il faut qu'elle ait accès à ces variables.
L'idée est, tout simplement, de ne pas passer à la fonction la valeur de ces variables, mais leur adresse. Ainsi, la fonction pourra accéder à la case mémoire de ces variables, et échanger les valeurs qui y sont stockées.
Pour cela, on a recours à des paramètres pointeurs. Voila comment on fait :
A l'exécution, ce code affiche :
Ainsi : la fonction
echanger_KO()
échange bien les valeurs des variables paramètrea
etb
, mais les variablesa
etz
de la fonction principale main() ne sont PAS échangées.Pourquoi ? Ce slide rappelle ce qui se passe lors de l'appel de la fonction.
Lorsque la ligne 15 est exécutée, il existe deux variables en mémoire :
TODO imageLa ligne 15 affiche donc :
La ligne 16 lance l'exécution de la fonction, en passant en paramètre à la fonction les valeurs des variables
a
etz
du main(), c'est à dire les valeurs entières1
et2
.Durant l'exécution d'une fonction, de nouvelles variables sont créées en mémoire : une pour chaque paramètre de la fonction, et une pour chaque variable locale à la fonction.
Dans notre cas, pendant l'exécution de la fonction, il existe donc 3 nouvelles variables en mémoire :
TODO Imagea
,b
etz
.[En savoir plus] ces nouvelles variables sont créés dans une zone mémoire particulière appéle "pile d'appel de fonction".
Pour le moment,
c
n'a pas été initialisé.Les variables-paramètre
a
etb
de la fonction ont elles pour valeur les valeurs passées lors de l'appel de la fonction par le main(), c'est à dire 1 et 2.On peut remarquer que durant l'exécution de notre fonction il existe en mémoire DEUX variables nommées
a
en mémoire : celle crée par la fonction main() et celle créée par la fonction echanger_KO(). D'ailleurs, bientôt, elles n'auront plus les mêmes valeurs !Ce n'est pas un problème. Ce ne sont pas les mêmes variables.
Reprenons le fil. La ligne 4 affiche :
La ligne 5 initialise la valeur de c :
TODOLa ligne 6 affecte la valeur de b à la variable a :
TODOTODO La ligne 7 change la valeur de b, en lui affectant l'ancienne valeur de a, qu'on avait pris soin de stocker dans la variable "pivot" c.
TODOEn résumé, le code des lignes 5 à 7 de la fonction échange donc bien le contenu des variables
a
etb
de la fonction.Et la ligne 8 affiche donc :
Lorsque l'exécution d'une fonction se termine, toutes les variables nécessaire à son exécution sont détruites en mémoire.
Dans notre cas, les variables
TODOa
b
etc
de la fonction sont détruites :Puis on retourne au main(), et on passe à l'instruction qui suit l'appel de la fonction.
Notez que les variables du main() n'ont pas été modifiées par l'appel de la fonction !
Le dernier printf() affiche donc :
Ainsi donc, la fonction a bien échangé ses variables-paramètre ... Mais n'a pas échangé les variables du main !
a
etz
du main(), mais les valeurs de ces variables.En fait, l'appel de fonction ligne 16 aurait pu tout aussi bien être fait directement avec ces valeurs comme ceci :
Cela n'aurait rien changé du tout !