Documente Academic
Documente Profesional
Documente Cultură
2.1 Introduction
En C++, lorsque l’on modifie un paramètre dans une fonction, si l’on souhaite que les modi-
fications soient effectives dans le reste du programme, il faut passer le paramètre par référence.
� �
Ainsi, l’exécution du code :
1 void change(int & nb)
2 {
3 cout << "nb = " << nb << endl;
4 nb = 3;
5 cout << "nb = " << nb << endl;
6 }
7
8 int main()
9 {
10 int i = 5;
11 cout << "i = " << i << endl;
12 change(i);
13 cout << "i = " << i << endl;
14 return 0;
� �
15 }
� �
affichera :
1 i = 5
2 nb = 5
3 nb = 3
� �
4 i = 3
Malheureusement, le passage par référence n’existe pas en C. Pour que la modification d’une
variable passée en paramètre se répercute dans le programme, il faut alors passer à la fonction
l’adresse de cette variable. Le type du paramètre n’est pas du même type que la variable (ex :
float) mais un pointeur (pointant sur des valeurs de même type que la variable que l’on souhaite
modifier, par exemple float *).
Ainsi, si v est une variable (de type int) que l’on veut faire modifier par une fonction f, on
passe à f comme valeur d’argument l’adresse &v de v. On doit donc déclarer que le paramètre
� �
correspondant de f est un pointeur :
� �
1 void f(int *p) { ... *p ...}
Cette fonction est appelée f(&v). Le passage de l’argument &v se fait par copie, ce qui fait
que l’adresse de v est copiée dans p. Dans le corps de la fonction, à chaque fois que *p est lue ou
17
IUT de Villetaneuse
écrite, c’est donc la variable d’adresse &v qui est lue ou écrite, c’est-à-dire v. Ce mode de passage
des arguments est appelé passage par adresse.
Exemple 1
Modifions la fonction change définie ci-dessus de manière à transmettre le paramètre par
� �
adresse :
1 #include "iutv.h"
2 void change(int *p)
3 {
4 cout << "*p = " << *p << endl;
5 *p = 3;
6 cout << "*p = " << *p << endl;
7 }
8
9 int main()
10 {
11 int i = 5;
12 cout << "i = " << i << endl;
13 change(&i);
14 cout << "i = " << i << endl;
15 return 0;
� �
16 }
i p
i (main) (change)
(main) 5
5
(a) Après exécution de la ligne 11
(b) Avant exécution de la ligne 5
i p
(main) (change) i
3 (main)
3
(d) Après exécution de la ligne 13
(c) Après exécution de la ligne 5
Observons pas à pas ce qui se passe lorsque le code de l’exemple est exécuté :
1. La ligne 11 déclare une une variable entière nommée i, et l’initialise avec la valeur 5.
2. Lors de l’appel de la fonction change, on passe en paramètre l’adresse de la variable i.
3. Lors de l’exécution du corps de la fonction change, p contient l’adresse de la variable i.
4. L’instruction de la ligne 4 affiche la valeur de i, à savoir 5.
5. La ligne 5 modifie le contenu de la case mémoire pontée par p. Comme le pointeur p contient
l’adresse de la variable i, cela modifie alors la variable i pour mettre 3.
6. L’instruction 6 affiche le contenu *p de la case mémoire pointée par p, soit 3.
7. A la fin d’appel de la fonction, la variable p est détruite et l’état de la mémoire est celui
indiqué dans la figure 2.1(d).
� �
Langage C �18 � 1ère année (2013/2014)
Département informatique
Exemple 2
Écrivons maintenant une fonction echange, échangeant les valeurs de deux variables entières,
en utilisant les pointeurs :
� �
1 #include "iutv.h"
2
10 int main()
11 {
12 int a=1;
13 int b=2;
14
15 echange(&a, &b);
16 cout << a << "\t" << b << endl;
17 return 0;
� �
18 }
Remarque : Le passage par adresse en C est plus lourd que le passage par référence en C++,
mais il a l’avantage d’être explicite à l’appel de la fonction : quand on voit un appel echange(&a,
&b), il est clair qu’il s’agit d’un appel par adresse, tandis qu’en C++, devant un appel echange(a,
b), il faut aller voir la déclaration de la fonction pour savoir s’il s’agit d’un appel par référence ou
d’un appel par copie.
� �
5 };
� �
L’instruction :
� �
1 struct etudiant *pp;
déclare une variable de nom pp qui est un pointeur sur le type structuré struct etudiant. Ce
� �
pointeur peut alors contenir l’adresse d’une variable de type struct etudiant :
1 struct etudiant e1 = {"Dupond","Martin"};
� �
2 pp = &e1;
� �
On peut alors accéder aux champs de la variable e1 à l’aide du pointeur pp :
� �
1 cout<< "Nom: " << (*pp).nom << ", prénom: "<<(*pp).prenom << endl;
� �
1ère année (2013/2014) �19 � Langage C
IUT de Villetaneuse
Attention : L’opérateur . étant prioritaire sur l’indirection *, les parenthèses sont obligatoires.
Mais il y a une autre notation. Au lieu de (*pp).nom, on utilise l’opérateur -> pour écrire plus
� �
simplement :
� �
1 cout<< "Nom: " << pp->nom << ", prénom: "<<pp->prenom << endl;
9 cout<< "Nom :" << pp->nom << endl; /* Affiche le nom du 21e étudiant */
10 pp=pp+1; /* pp pointe le 22ième étudiant */
11
12 cout<< "Nom :" << pp->nom << endl; /* Affiche le nom du 22e étudiant */
13
17 cout<< "Nom :" << pp->nom << endl; /* Affiche le nom du 2ème étudiant */
18
� �
21 cout<< "Nom :" << pp->nom << endl; /* Affiche le nom du 4ième étudiant */
15 int main ()
16 {
17 struct point p1 = {3,8};
1. En fait, l’incrémentation décale le pointeur du nombre d’octets égal à l’occupation mémoire du type structuré
pointé.
� �
Langage C �20 � 1ère année (2013/2014)
Département informatique
18 deplX = 4;
19 deplY = 9;
20 deplacerPoint (&p1, deplX, deplY);
21 return 0;
� �
22 }
Observations :
1. Le programme appelant passe trois paramètres à la fonction deplacerPoint() :
– &p1, c’est-à-dire l’adresse de la variable structurée p1, dans l’exemple cette adresse vaut :
4500,
– deplX et deplY, deux entiers transmis par valeur qui valent respectivement 4 et 9.
2. p->x permet d’accéder au champ x de la variable structurée du programme appelant, c’est-
à-dire la variable p1 dont l’adresse est 4500.
Ainsi p->x += dx; ajoute deplX au champ x de la variable p1 du programme appelant,
Ainsi p->y += dy; ajoute deplY au champ y de la variable p1 du programme appelant.
3. Finalement, la transmission par copie de l’adresse de la variable structurée p1 a permis à la
fonction de modifier indirectement la variable p1 du programme appelant.
en mémoire centrale
p1
4500
/3 7 /8 17
deplX deplY
4 9
Environnement Appelant
p dx dy
4567
4500 4 9
Environnement Appelé
Remarque : Même si l’on ne modifie pas une variable structurée passée en paramètre, il peut
être intéressant de passer cette variable par adresse si le type structuré occupe beaucoup d’espace
mémoire. En effet, dans ce cas, plutôt que de copier les champs de la variable, le programme copie
uniquement l’adresse de cette variable. Cela permet d’accélérer l’exécution du programme.
� �
1ère année (2013/2014) �21 � Langage C
IUT de Villetaneuse
� �
5 }
� �
Soit le programme principal suivant
1 int main()
2 {
3 int a = 8;
4 int b = 2;
5 int c = 4;
6 faitQuoi (a, b, c);
7 cout << "a=" << a << " b=" << b << endl;
8
9 return 0;
� �
10 }
� �
Question 1.2 : Même question lorsque la fonction est définie par
1 void faitQuoiBis(int *px, int *py, int d)
2 {
3 *px = *px + d;
4 *py = *py + d;
� �
5 }
� �
et la fonction main par
1 int main()
2 {
3 int a = 8;
4 int b = 2;
5 int c = 4;
6 faitQuoiBis (&a, &b, c);
7 cout << "a=" << a << " b=" << b<<endl;
8
9 return 0;
� �
10 }
Exercice 2 : Factorielle
Écrire une fonction factorielle void factorielle(int n, int * reponse) qui calcule la fac-
torielle d’un entier et écrire un programme de test qui l’utilise.
Exercice 3 : Échange
� �
Langage C �22 � 1ère année (2013/2014)
Département informatique
1. Écrire une fonction C qui échange deux nombres réels (double). Tester un programme
principal appelant cette fonction.
� �
1ère année (2013/2014) �23 � Langage C
IUT de Villetaneuse
� �
Langage C �24 � 1ère année (2013/2014)