Chapitre 6 Corrige
Chapitre 6 Corrige
Chapitre 6 Corrige
6.1 Rappel
– Pour définir une fonction en C++, on précise tout d’abord le type de la valeur retournée
par la fonction. Si la fonction ne renvoie aucun résultat, le type est alors void (signifiant
"vide" en anglais). Le nom de la fonction est suivi de parenthèses entre lesquelles on précise
les paramètres ainsi que leur type. Les parenthèses sont obligatoires, même s’il n’y a aucun
paramètre.
– En C++, au maximum une valeur peut être retournée par la fonction. Nous verrons
dans ce chapitre comment transmettre d’autres valeurs de sorties au programme appelant.
– Il est possible de déclarer des variables locales. Ces variables ne sont accessibles que dans le
corps de la fonction, cela signifie qu’elle naissent au moment de leur déclaration et qu’elles
sont détruites une fois la dernière instruction de la fonction exécutée. C’est pour cela qu’on
les appelle des variables locales.
105
IUT de Villetaneuse
paramètre. Ainsi, si l’on souhaite que la modification d’un paramètre dans la fonction se répercute
dans le reste du programme, il faut alors passer le paramètre par référence. Dans ce cas, la
fonction ne travaille plus sur une copie mais directement sur la variable. Pour cela, il
� �
faut rajouter le caractère & entre le type et le nom du paramètre. Ainsi, l’exécution du code :
1 void change(int &i)
2 {
3 cout << "i = " << i << endl;
4 i = 3;
5 cout << "i = " << i << endl;
6 }
7
8 int main()
9 {
10 int i;
11 i = 5;
12 cout << "i = " << i << endl;
13 change(i);
14 cout << "i = " << i << endl;
15 return 0;
� �
16 }
� �
affiche le résultat :
1 i = 5
2 i = 5
3 i = 3
� �
4 i = 3
i
i (main, change)
(main)
5
5
(a) Après exécution de la ligne 11 (b) Avant exécution de la
ligne 4
i
(main,change) i
(main,change)
3
3
(c) Après exécution de la (d) Après exécution de la ligne 13
ligne 4
Dans la fonction main est déclarée une variable i, initialisée ligne 11. L’état de la mémoire après
l’exécution de cette instruction est décrit dans la figure 6.1(a). Seule la variable i de la fonction
main est présente en mémoire et sa valeur est 5. L’instruction ligne 12 affiche i=5. La fonction
change est ensuite appelée avec passage par référence & i. La variable locale de la fonction qui
s’appelle également i, partagera le même espace mémoire que la variable i déclarée dans la fonc-
tion main (instruction 11). L’état de la mémoire correspond à celui indiqué dans la figure 6.1(b).
L’instruction ligne 3 affiche donc i=5. Puis, la valeur du seul espace mémoire partagé par les deux
fonctions est changée ligne 4 (voir figure 6.1(c)). La ligne 5 affiche alors i=3. À ce moment-là,
l’exécution de change est terminée et entraîne la modification de la variable passée en paramètre
qui porte le même nom i. Alors, après l’exécution de la ligne 13, la variable i de la fonction main
est modifiée comme décrit par la figure 4.2(d). La ligne 14 affiche donc i=3.
� �
Intro à l’algorithmique et à la programmation �106 � 1er semestre
Departement informatique
Le passage par référence est important car il permet de transmettre plusieurs valeurs de
sortie au programme appelant même si une seule valeur peut être retournée par la fonction. Ainsi,
� �
le code d’une fonction calculant l’aire et le périmètre d’un rectangle peut être :
1 void airePerimetreRectangle(double longueur, double largeur, double &aire, double &perim)
2 {
3 aire = longueur * largeur;
4 perim = 2 * (longueur + largeur);
5 }
6
7 int main()
8 {
9 double a, p;
10 airePerimetreRectangle(10.0,4.5,a,p);
11 cout << "Aire du rectangle : " << a << ", périmètre : " << p << endl;
12 return 0;
� �
13 }
� �
1er semestre �107 � Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
Question 1.2 : Quel est le rôle du symbole & utilisé dans les arguments d’une fonction donnée.
Correction :
Cela indique que la variable elle-même est passée en paramètre et qu’elle ne sera pas copiée localement au sein de
la fonction �
� �
Question 1.3 : Déterminez ce qu’affiche ce programme.
1 void affiche2int(int a, int b)
2 {
3 cout<<a <<"-->" <<b<<endl;
4 }
5 void incr1(int x)
6 {
7 x=x+1;
8 }
9 void incr2(int& x)
10 {
11 x=x+1 ;
12 }
13 void decr1(int x)
14 {
15 x=x-1;
16 }
17 void decr2(int& x)
18 {
19 x=x-1;
20 }
21
22 int main()
23 {
24 int i = 1;
25 int j = 1;
26 affiche2int ( i , j);
27 incr2(i);
28 affiche2int ( i , j);
29 decr1(j);
30 affiche2int ( i , j);
31 decr2(j);
32 affiche2int ( i , j);
33
34 while (i != j)
35 {
36 incr1(j);
37 decr2(i);
� �
Intro à l’algorithmique et à la programmation �108 � 1er semestre
Departement informatique
38 }
39 affiche2int ( i, j);
40 return 0;
� �
41 }
Correction :
� �
1 1-->1
2 2-->1
3 2-->1
4 2-->0
� �
5 0-->0
�
Question 1.4 : Que se passe t-il si on transforme l’en-tête de la fonction decr2 envoid decr2(int
x) ?
Correction :
la variable x est alors copiée localement et n’est plus modifiéepar la fonction. �
6 int main()
7 {
8 int n = 4;
9 cout << "res = " << somme2nb(n,3) << endl;
10 return 0;
� �
11 }
Correction :
Le programme n’affiche rien car il y a une erreur. En effet, lors de l’appel de la fonction somme2nb, le deuxième
paramètre est une constante (nombre 3) alors que le deuxième paramètre, passé par référence, implique que l’on
doit passer une variable. Il ne faut passer par référence que des paramètres que l’on va modifier et appeler les
fonctions avec des variables pour tous les paramètres passsés par référence. �
� �
6 }
�
� �
1er semestre �109 � Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
� �
Correction :
1 void calcul(double a, double b, double & moy, double & max, double & min)
2 {
3 moy=(a+b)/2;
4 if (a>b)
5 {
6 max=a;
7 min=b;
8 }
9 else
10 {
11 min=a;
12 max=b;
13 }
� � �
14 }
Question 3.2 : On veut maintenant avoir uniquement deux variables qui utilisent le passage par
référence (le minimum et le maximum). Que proposez-vous pour renvoyer la valeur de la moyenne ?
� �
Correction :
1 double calcul(double a, double b, double & max, double & min)
2 {
3 if (a>b)
4 {
5 max=a;
6 min=b;
7 }
8 else
9 {
10 min=a;
11 max=b;
12 }
13 return (a+b)/2;
� � �
14 }
� �
Correction :
1 void echange(int &a, int &b)
2 {
3 int tmp = a;
4 a = b;
5 b = tmp;
� �
6 }
� �
Intro à l’algorithmique et à la programmation �110 � 1er semestre
Departement informatique
Question 4.2 : Ecrivez la fonction void tri(int &a, int & b, int &c) qui permute les va-
leurs de a, b et c de sorte que a ≤ b ≤ c. Vous utiliserez la fonction void echange(int & x, int
&y).
� �
Correction :
1 void tri(int &a, int & b, int &c)
2 {
3 if (a>b)
4 echange(a,b);
5 if (b>c)
6 {
7 echange(b,c);
8 if (a>b)
9 echange(a,b);
10 }
� � �
11 }
� � �
5 }
� � �
6 }
� �
1er semestre �111 � Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
� �
Correction :
� �
16 }
�
Question 7.2 : Définir la fonction afficheHeure prenant en paramètre une heure (décrite par
les trois variables) et l’affichant sous la forme heure:minute:seconde.
� �
Correction :
� �
4 }
�
Question 7.3 : Écrire un programme principal déclarant les trois variables h, min, sec initiali-
sée à 0 heure, 0 minute et 0 secondes. Ajouter 100 fois une seconde et afficher les différentes heures
obtenues.
� �
Correction :
1 int main()
2 {
3 int h=0, min=0,sec=0;
4 for (int i = 0 ; i < 100 ; i++)
5 {
6 ajouteUneSeconde(h,min,sec);
7 afficheHeure(h,min,sec);
8 }
9 return 0;
� �
10 }
� �
Intro à l’algorithmique et à la programmation �112 � 1er semestre
Departement informatique
� � Exercice 8 : Jeu du 21
Le jeu du 21 est une version simplifiée du jeu de dés appelé le 421. Le jeu du 21 se joue avec
deux dés et deux joueurs. À chaque combinaison de dés est associé un score. Chaque joueur a 3
lancés de dés pour obtenir le meilleur score possible (associé à la combinaison de dés obtenue). Le
perdant est celui qui ne parvient pas à obtenir un score au moins égal à celui obtenu précédemment
par l’adversaire.
Les scores sont obtenus par combinaison des deux dés. La meilleure combinaison est un 2 et
un 1. Les combinaisons suivantes sont les doubles (double 6, double 5, ..., double 1). Le reste des
combinaisons est ordonné par le chiffre le plus grand puis par le deuxième chiffre. Voici la liste
complète des combinaisons possibles (de la meilleure à la moins bonne) :
2-1, 6-6, 5-5, 4-4, 3-3, 2-2, 1-1, 6-5, 6-4, 6-3, 6-2, 6-1, 5-4, 5-3, 5-2, 5-1, 4-3, 4-2, 4-1, 3-2.
Le joueur dont c’est le tour commence par lancer les deux dés. Il peut alors décider d’effectuer
une relance, c’est-à-dire de relancer un des deux dés ou les deux. Son tour se termine après
maximum deux relances et on ne considère que la combinaison de dés obtenue à la fin de son tour.
Question 8.1 : Écrire une fonction permettant à l’utilisateur de saisir les dés qu’il souhaite
relancer : 0 s’il ne veut faire aucune relance, 1 s’il souhaite relancer uniquement le premier dé, 2
s’il souhaite relancer uniquement le deuxième dé et 3 s’il souhaite relancer les deux dés. Le choix
de l’utilisateur sera retourné par la fonction.
� �
Correction :
1 int saisieChoix()
2 {
3 int nb = -1;
4 while (nb < 0 or nb > 3)
5 {
6 cout << "Faites votre choix :" << endl;
7 cout << " 0 - Aucun dé relancé" << endl
8 << " 1 - Relancer le premier dé" << endl
9 << " 2 - Relancer le deuxième dé" << endl
10 << " 3 - Relancer les deux dés" << endl;
11 saisie(nb);
12 }
13 return nb;
� � �
14 }
Question 8.2 : Reprendre la fonction lancerDe définie dans la question 3.1 du chapitre précédent.
Écrire ensuite une fonction lancerDesChoix prenant en paramètre le résultat d’un lancer de dés
ainsi que le choix de l’utilisateur (nombre compris entre 0 et 3), et relançant les dés nécessaires.
� �
Correction :
1 void lancerDesChoix(int& de1, int& de2, int choix)
2 {
3 //Si le choix est 0, on ne fait rien
4 if (!choix)
5 return;
6
7 //Relancer le premier dé
8 if (choix != 2)
9 de1 = lancerDe();
10
11 if (choix != 1)
� �
1er semestre �113 � Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
12 de2 = lancerDe();
� � �
13 }
Question 8.3 : Écrire la fonction lancerDes qui lance les deux dés en utilisant la fonction
précédente
� �
Correction :
1 void lancerDes(int& de1, int& de2)
2 {
3 lancerDesChoix(de1,de2,3);
� � �
4 }
Question 8.4 : Écrire une fonction afficherUnDe qui affiche le dé passé en paramètre sous forme
"graphique". Ainsi, si la valeur du dé est 5, la fonction doit afficher :
/////////
/ * * /
/ * /
/ * * /
/////////
� �
Correction :
1 void afficherUnDe(int de)
2 {
3 cout << "/////////"<<endl;
4 if (de==1)
5 cout << "/ /" << endl << "/ * /" << endl << "/ /" << endl;
6 else if (de==2)
7 cout << "/ * /" << endl << "/ /" << endl << "/ * /" << endl;
8 else if (de==3)
9 cout << "/ * /" << endl << "/ * /" << endl << "/ * /" << endl;
10 else if (de==4)
11 cout << "/ * * /" << endl << "/ /" << endl << "/ * * /" << endl;
12 else if (de==5)
13 cout << "/ * * /" << endl << "/ * /" << endl << "/ * * /" << endl;
14 else
15 cout << "/ * * /" << endl << "/ * * /" << endl << "/ * * /" << endl;
16 cout << "/////////"<<endl;
� � �
17 }
Question 8.5 : Écrire la fonction afficherDes qui affiche sous forme graphique le résultat d’un
lancer de dés.
� �
Correction :
1 void afficherDes(int de1, int de2)
2 {
3 afficherUnDe(de1);
4 cout << endl;
5 afficherUnDe(de2);
6 cout << endl << endl;
� � �
7 }
� �
Intro à l’algorithmique et à la programmation �114 � 1er semestre
Departement informatique
Question 8.6 : Il est nécessaire, pour comparer les combinaisons de dés adversaires, d’associer à
toute combinaison de dés un score. Ce score doit respecter l’ordre des combinaisons, c’est-à-dire
qu’une combinaison meilleure qu’une autre doit avoir un score plus grand. Par exemple, le score
associé à la combinaison 1-1 doit être supérieur au score associé à la combinaison 6-5. Déterminer
une manière simple de calculer un tel score pour une combinaison de dés donnée. Définir une
fonction retournant le score associé à une combinaison de dés passée en paramètre.
� �
Correction :
� �
14 }
�
Question 8.7 : Définir une fonction tour simulant le tour d’un joueur. Cette fonction prendra en
paramètre un booléen valant true si c’est le tour du premier joueur, et false sinon. La fonction
devra afficher Tour du joueur suivi du numéro du joueur (1 ou 2). Elle permettra ensuite au
joueur de lancer les dés, d’effectuer les relances si nécessaire puis retournera le score obtenu par
le joueur.
� �
Correction :
� �
26 }
� �
1er semestre �115 � Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
� � �
19 }
� � �
6 }
� �
Intro à l’algorithmique et à la programmation �116 � 1er semestre
Departement informatique
� �
Correction :
1 int Saisie(int min, int max)
2 {
3 int nb = min-1;
4 while (nb < min || nb > max)
5 {
6 cout << "Saisir un nombre entre " << min << " et " << max << endl;
7 Saisie(nb);
8 }
9 return nb;
� � �
10 }
Question 9.2 : Écrire une fonction permettant d’initialiser le nombre de lignes et de colonnes
de la tablette avec des valeurs aléatoires comprises entre 5 et 20 pour le nombre de lignes et entre
10 et 30 pour le nombre de colonnes. De plus, le nombre de lignes doit être différent du nombre
de colonnes. Pour générer un nombre aléatoire, utiliser la fonction rand() (c.f., TD précédent,
exercice nombre magique).
� �
Correction :
1 void initialiseJeu(int & nL, int & nC)
2 {
3 //Nombre aléatoire entre 5 et 20
4 nL = 5 + rand()%16;
5
� � �
10 }
� � �
14 }
� �
1 void afficheTablette(int nL, int nC)
2 {
3 if (nL > 0 && nC > 0)
4 {
5 int i = 0 ;
6 while (i<nL)
7 {
8 afficheLigneTablette(i,nC);
9 i++;
10 }
11 }
� � �
12 }
Question 9.5 : Écrire une fonction perdu() qui prend en paramètre le nombre de lignes et de
colonnes de la tablette et retourne 1 si le joueur a perdu (le nombre de lignes et le nombre de
colonnes sont égaux à 1), 0 sinon.
� �
Correction :
1 int perdu(int nL, int nC)
2 {
3 return nL <= 1 && nC <= 1;
� � �
4 }
Question 9.6 : À chaque tour, un joueur doit choisir s’il supprime des lignes ou des colonnes.
Pour exprimer ce choix, l’utilisateur devra saisir l’entier 0 s’il choisit de supprimer des lignes, ou
l’entier 1 pour les colonnes. Écrire une fonction saisieLigneOuColonnes() prenant en paramètre
le nombre de lignes et de colonnes de la tablette. Cette fonction effectuera une saisie répétée
(utilisation de la fonction Saisie()) jusqu’à ce que l’utilisateur ait saisi 0 ou 1. De plus, s’il ne
reste qu’une seule ligne ou qu’une seule colonne, alors aucun choix ne sera proposé au joueur. La
fonction renverra 0 si l’utilisateur a choisi de supprimer des lignes, et 1 sinon.
� �
Correction :
1 int saisieLigneOuColonnes(int nL, int nC)
2 {
3 if ( nL == 1 )
4 {
5 cout << "Vous ne pouvez prendre que des colonnes" << endl;
6 return 1;
7 }
8 else if (nC == 1)
9 {
10 cout << "Vous ne pouvez prendre que des lignes" << endl;
11 return 0;
12 }
13 else
14 {
15 cout << "Lignes (0) ou colonnes (1)" << endl;
16 return Saisie(0,1);
17 }
� � �
18 }
� �
1 int main ()
2 {
3 //Initialisation du générateur aléatoire
4 srand(time(NULL));
5
21 //Affichage de la tablette
22 afficheTablette(nombreLignes,nombreColonnes);
23
33 //Changement de joueur
34 joueur = joueur == 0;
35 }
36 cout << "JOUEUR " << joueur+1 << " A PERDU" << endl;
37
38 return 0;
� � �
39 }
Question 9.8 : Il existe une stratégie gagnante pour ce problème. Déterminer cette stratégie
gagnante et programmer une version du jeu de la tablette pour un joueur de manière à ce que
le joueur perde systématiquement, quel que soit le nombre de lignes ou de colonnes qu’il retire
durant la partie (On suppose que l’ordinateur commence à jouer).
Correction :
Stratégie gagnante : ramener à chaque itération la tablette à un carré. Le dernier carré sera le carré 1 * 1 et le
joueur aura perdu. Comme le nombre de lignes et de colonnes sont différents en début de partie (voir la description
de la fonction initialiseJeu()) et que l’ordinateur commence, cette stratégie est toujours "réalisable". �
� �
1er semestre �119 � Intro à l’algorithmique et à la programmation