Les pointeurs |
Nous abordons ce mois-ci la notion la plus
complexe du C mais aussi la plus importante : les pointeurs.
Accrochez-vous c'est parti ! Nous avons déjà un peu utilisé précédemment le principe des pointeurs avec l'operateur d'adressage & qui désigne l'adresse d'un lvalue. Nous allons voir que le C permet de manipuler des adresses mémoires par l'intermédiaire de variables que l'on appelle "pointeur". |
Sommaire |
les opérateurs '&' et '*' |
D'une manière générale la
déclaration d'un pointeur se fait de cette manière :
|
<type de la donnée> *<nom de la variable> |
L'opérateur '*' a une tout autre
signification que la multiplication, il signifie littéralement ici "est un pointeur
vers".
|
int *pointeur ; |
signifie "la variable "pointeur" pointe vers une
donnée de type int".
Le reste du temps '*' devant le nom d'un pointeur désigne le contenu de l'adresse pointée, c'est à dire le contenu d'une variable de type int. Nous ne reviendrons pas sur l'opérateur '&' qui permet de connaître l'adresse d'une variable. Voyons plutôt un exemple simple concret : |
//déclarer un pointeur pouvant contenir l'adresse d'une variable short short * pointeur ; //déclarer une variable de type short short variable ; //donner une valeur à la variable variable = 50 ; //faire pointer le pointeur sur la variable " variable " pointeur = &variable ; //ajouter 30 à la donnée se trouvant à l'adresse contenue // dans le pointeur (soit celle de la variable "variable") *pointeur+=30 ; |
Il est à noter que pour la dernière
intruction '*pointeur+=30' equivaut donc à 'variable+=30', de même il est important
de ne pas confondre l'adresse d'un pointeur (soit son emplacement dans la mémoire de
l'ordinateur) et l'adresse pointée par un pointeur (soit le contenu d'un pointeur
correspondant généralement à une variable).
Enfin un erreur est souvent commise lorsqu'on manipule les pointeurs. Celle-ci est souvent à l'origne de plantages sérieux de votre OS. |
//déclarer un pointeur pouvant contenir l'adresse d'une variable short short * pointeur ; //déclarer une variable de type short short variable ; //donner une valeur à la variable variable = 50 ; //faire pointer le pointeur sur la variable " variable " pointeur = &variable ; /*prendre l'adresse du pointeur, l'augmenter de 30, se retrouver sur l'adresse d'une variable totalement inconnue que l'on risque de manipuler : ERREUR ! ! !*/ pointeur+=30 ; |
On voit bien ici les conséquences
désastreuses que peuvent avoir ce genre d'erreur. Avec des OS peu surs c'est le plantage
garanti (qui à dit Windows 9x ? J )
|
![]() le principe des pointeurs |
les pointeurs et les fonctions |
Comme nous l'avons déjà dit une
fonction appelée n'a aucun moyen de modifier la variable d'une fonction appellante.
Prenons l'exemple d'une fonction qui échange le contenu de deux variables passés en paramètre par une fonction appellante. Comme le montre le shéma ci-contre ce genre de fonction ne fait rien du tout : |
void echanger (int variable1, int variable2) { //créer une variable temporaire pour contenir //le contenu d'une des deux variables à echanger int temp ; //mettre le contenu de la variable 1 dans la temporaire temp = variable1 ; //remplacer le contenu de la variable1 par celui de la variable2 variable1 = variable2 ; //donner à variable2 l'ancienne valeur de variable1 variable2 = temp ; } //fin de la fonction toute la mémoire prise par les variables // a été libérée aucun changement n'a été éffectué |
ici on ne manipule qu'une copie des variables
passée en argument par la fonction appellante. Dès que la fonction appelée
se termine, les variables créées dans cette fonction disparaissent emportant avec
elles les changements. Les variables de la fonction appellante qui devaient être
échangées ne le sont donc pas.
Les pointeurs parent ce problème très efficacement : |
void echanger (int *pointeur1, int *pointeur2) { //créer une variable temporaire pour contenir // le contenu d'une des deux variables à echanger int temp ; //mettre le contenu de la variable pointée par pointeur1 dans la temporaire temp = *pointeur1 ; //remplacer le contenu de la variable pointée //par pointeur1 par celui de la variable pointée par pointeur2 *pointeur1 = *pointeur2 ; //donner à pointeur2 l'ancienne valeur de pointeur1 *pointeur2 = temp ; } //fin de la fonction |
La fonction ne manipule plus ici une copie des
variables mais bien deux variables dont elle a reçu les adresses par passage d'argument de
la fonction appellante.
Elle va donc modifier des variables à une adresse précise et cette adresse se trouve être celle des variables de la fonction appellante. En se finissant la fonction appellée va liberer la mémoire prise par la variable temp et par les pointeurs mais les variables de la fonction appellante ne seront pas touchées et garderont leurs modifications. |
![]() les pointeurs et les fonctions |
Quelques petites remarques |
Dans la dernière version de la fonction
echanger nous n'avons aucune raison de changer les adresses vers lesquelles pointent les
pointeurs pointeur1 et pointeur2, nous pourrions donc les mettre en 'const' afin de garantir une
certaine securité :
|
void echanger(int * const pointeur2, int * const pointeur2); |
Ecrire 'int * const a' signifie que le pointeur
'a' pourra désigner une variable possédant différentes valeurs au cours de
sa vie mais l'adresse qu'il pointe ne pourra pas changer.
Au contraire, ecrire 'const int * a' signifie que c'est le contenu de la variable pointée par 'a' qui ne pourra pas changer, alors que l'adresse pourrait changer. |
Nous continuerons sur les pointeurs dans notre
prochain cours et nous aborderons les structures, l'une des dernières notions qu'il nous
reste à apprendre avant la fin des cours sur le langage C
|
par Valentin BILLOTTE vbillotte@programmationworld.com http://www.programmationworld.com Dernière mise à jour: |