Chapitre 4 avec exercices corrigés

Download Report

Transcript Chapitre 4 avec exercices corrigés

Introduction à l’algorithmique et à la programmation
Cours avec corrigés
1ère année
IUT de Villetaneuse.
Hanène Azzag,
Frédérique Bassino,
Pierre Gérard,
Bouchaïb Khafif,
Mathieu Lacroix,
Mustapha Lebbah,
Guillaume Santini.
11 septembre 2014
IUT de Villetaneuse
Intro à l’algorithmique et à la programmation
66 1er semestre
Chapitre 4
Fonctions
Une fonction est une portion de code (séquence d’instructions) effectuant une tâche précise
(un calcul par exemple). De nombreuses fonctions sont déjà définies (dans des bibliothèques) dans
le langage C++, telle que abs() par exemple. Les fonctions permettent de réutiliser les portions
de code effectuant la tâche, aussi souvent qu’on le souhaite et à n’importe quel endroit dans le
programme. De plus, les fonctions permettent de structurer le programme et de le rendre plus
clair.
Par exemple, si l’on souhaite faire la somme des valeurs absolues de deux nombres saisis par
l’utilisateur, il est plus clair d’écrire
1
2
3
4
5
double nb1, nb2, res;
cout<<"Donnez une premier nombre réel";
saisie(nb1);
cout<<"Donnez un deuxième nombre réel";
saisie(nb2);
6
7
res = abs(nb1) + abs(nb2);
8
9
1
2
3
4
5
cout << "Résultat : " << res << endl;
que
double nb1, nb2, res;
cout<<"Donnez une premier nombre réel";
saisie(nb1);
cout<<"Donnez un deuxième nombre réel";
saisie(nb2);
6
7
8
9
10
11
if (nb1 < 0)
nb1 *= -1;
if (nb2 < 0)
nb2 *= -1;
res = nb1 + nb2;
12
13
cout << "Résultat : " << res << endl;
Bien qu’un très grand nombre de fonctions soient définies en C++, il n’est pas toujours possible
de trouver une fonction qui fasse exactement ce que l’on souhaite. Par exemple, si l’on code un
jeu de cartes et que l’on souhaite connaître qui a le valet de carreau, il n’existe pas une fonction
permettant de faire ceci !
Heureusement, il est possible de définir ses propres fonctions. C’est l’objet de ce chapitre.
67
IUT de Villetaneuse
4.1
Concept de fonction
Lors de l’exécution ou appel d’une fonction :
1. le programme appelant (portion de code contenant l’appel de la fonction) s’arrête,
2. la fonction est alors exécutée avec certaines valeurs en entrée (généralement),
3. lorsque l’exécution de la fonction est terminée, des valeurs sont renvoyées au programme
appelant,
4. le programme appelant reprend son exécution.
Le processus est représenté dans la figure 4.1.
Entrées
Programme
appelant
Fonction
Sorties
Figure 4.1 – Déroulement du programme lors de l’appel d’une fonction
4.1.1
Définition et appel de fonction
Une fonction est caractérisée par :
– le type retourné par la fonction,
– un nom (les règles pour les noms de fonctions sont les mêmes que pour les noms de variables),
– des paramètres (donnés sous la forme d’une liste ordonnée, éventuellement vide, de leurs
noms précédés de leur type),
– un bloc d’instructions associé.
Le bloc d’instructions associé est l’ensemble des instructions qui seront exécutées lors de l’appel de la fonction. Les paramètres, appelés aussi arguments, sont utilisés comme des variables
initialisées et vont permettre de modifier le comportement du bloc d’instructions.
1
2
La définition d’une fonction est de la forme :
typeRetour nomDeFonction (type1 param1, type2 param2, ...)
{/* le bloc d’instructions de la fonction est délimité par une accolade ouvrante
* et une accolade fermante
*/
3
4
5
I1
I2
....
In
6
7
8
9
10
// ici, on écrit du code utilisant les paramètres
}// le code de la fonction s’arrête à l’accolade fermante
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 type de retour est suivi du nom de la fonction. Ce nom doit être unique, c’est-à-dire que
deux fonctions ne peuvent pas avoir le même nom. Le nom 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. Un bloc d’instructions entre accolades, qui forme le corps de la fonction, est
Intro à l’algorithmique et à la programmation
68 1er semestre
Departement informatique
obligatoire. Attention, même s’il n’y a qu’une seule instruction, les accolades sont obligatoires.
La ligne 1 est appelée en-tête de la fonction.
Remarque : En C++, au maximum une valeur peut être retournée par la fonction. Nous
verrons dans la suite comment envoyer d’autres valeurs de sorties au programme appelant.
Une fonction est appelée avec des valeurs de paramètres ou non : le programme appelant fournit
ou non des données à la fonction, et le déroulement de celle-ci ne sera pas le même suivant les
données fournies.
Voici un exemple de fonction :
1
2
3
4
5
6
7
8
void affiche_age(bool estHomme, string nom, int age)
{
if (homme)
cout << "Mr ";
else
cout << "Mme ";
cout << nom << " a " << age << " ans." << endl;
}
9
10
11
12
13
14
15
int main()
{
affiche_age(true,"Martin",23);
affiche_age(false,"Sophie",32);
return 0;
}
La fonction affiche_age() est définie avec les lignes 3 à 10. La ligne 3 correspond à l’en-tête
de la fonction et les lignes 4 à 10 au corps de la fonction. Cette fonction est appelée (exécutée)
deux fois et produit donc l’affichage :
1
2
Mr Martin a 23 ans.
Mme Sophie a 32 ans.
Remarques :
– Les définitions de fonctions doivent être écrites avant la définition de la fonction main. De
plus une fonction doit être définie avant d’être appelée.
– Une fonction peut appeler une autre fonction. Dans ce cas, elle joue le rôle de programme
appelant.
Paramètres et valeurs des paramètres
Il convient de bien distinguer les paramètres (on parle de paramètres formels) et les valeurs
des paramètres (on parle de paramètres effectifs) lors de l’appel de la fonction. Les paramètres
correspondent à ce qui se trouve entre parenthèses dans l’en-tête de la fonction. Ces paramètres
n’ont pas de valeur au moment de la définition de la fonction.
Lors de l’appel d’une fonction, l’utilisateur fournit les valeurs des paramètres. Ces valeurs
pourront changer à chaque appel.
Ainsi, dans l’exemple précédent, la fonction affiche_age() a trois paramètres formels en
entrée :
1. le premier est de type booléen et de de nom estHomme,
2. le second est de type chaîne de caractères et s’appelle nom,
3. le troisième est de type entier de nom age.
1er semestre
69 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
Lorsqu’on écrit le code de la fonction, on souhaite que estHomme indique si la personne est un
homme ou non, nom correspond au nom de la personne et age à son age. La fonction ne retourne
aucune valeur.
Lors du premier appel de la fonction (ligne 14), les valeurs des paramètres (paramètres effectifs)
sont true, "Martin" et 23. Pour le deuxième appel (ligne 15), les valeurs des arguments sont false,
"Sophie" et 32.
Les valeurs des paramètres doivent être du même type que ceux indiqués pour les paramètres
dans l’en-tête de la fonction. Dans le cas contraire, une conversion implicite de type est faite.
Remarque : On peut définir des fonctions ne prenant aucun paramètre.
I Sur ce thème : Exercice 1, questions 1.1 à 1.13, TD 5
I Sur ce thème : Exercice 2, TD 5
Valeur de retour
Une fonction peut être appelée pour calculer une valeur. C’est le cas de la fonction size() qui
calcule le nombre de caractères d’une chaîne de caractères. Il est alors nécessaire que la fonction
transmette la valeur calculée au programme appelant (flèche "Sortie" dans la figure 4.1). Pour
cela, on utilise l’instruction return suivie de la valeur à retourner. Attention, au plus une valeur
peut être retournée en C++. Voici un exemple de fonction retournant le périmètre d’un rectangle :
1
2
3
4
5
double perimetreRectangle(double longueur, double largeur)
{
double perimetre = 2 * (longueur + largeur);
return perimetre;
}
6
7
8
9
10
11
int main()
{
cout << "Le périmètre du rectangle est : " << perimetreRectangle(5.2,3.4) << endl;
return 0;
}
Attention : : Lorsque l’instruction return est exécutée, la fonction se termine. Autrement dit,
plus aucune autre instruction de la fonction n’est exécutée par la suite. De plus, l’instruction
return peut être utilisée même sans retourner aucune valeur.
I Sur ce thème : Exercice 1, questions 1.14 à 1.16, TD 5
I Sur ce thème : Exercice 2, TD 5
Fonction principale
La fonction main contient le programme principal. Elle est automatiquement appelée par le
système d’exploitation à l’exécution du programme. Sa valeur de retour est un code de retour d’état
d’exécution du programme qui peut être récupéré par le système d’exploitation. Si l’exécution est
correcte, la valeur retournée doit être 0. Une valeur non nulle correspond à un code d’erreur.
4.1.2
Portée des variables
La portée ou visibilité d’une variable est l’endroit dans le code où cette variable est accessible.
Une variable étant déclarée dans le corps d’une fonction (main ou autre), elle n’est visible (ou
accessible) qu’à l’intérieur de cette fonction. On dit que la variable est locale à la fonction. Il n’est
donc pas possible dans une fonction d’accéder à une variable locale à une autre fonction.
Les variables locales à une fonction seront créées à chaque appel de la fonction lors de leur
déclaration dans cette fonction puis détruites à la fin de l’appel. Par exemple, la compilation
du code
Intro à l’algorithmique et à la programmation
70 1er semestre
Departement informatique
1
2
void affiche_somme(int x, int y)
{ // Les paramètres en entrée x et y sont aussi des variables locales à la fonction !
3
int z = x + y;
4
// z est une variable locale à la fonction
5
cout << "La somme de " << x << " et " << y << " vaut " << z << endl;
6
7
}
8
9
10
11
12
13
14
1
2
3
4
int main()
{
affiche_somme(7,5); // Attention ! deux paramètres, 7 et 5
cout << z << endl;
return 0;
}
produira l’erreur suivante :
tmp.cpp:419:11: error: use of undeclared identifier ’z’
cout << z << endl;
^
1 error generated.
puisque z est une variable locale à affiche_somme et n’existe plus après l’appel de cette fonction.
De la même manière, il n’est pas possible d’accéder dans une fonction à une variable déclarée
dans la fonction main (ou une autre fonction). La compilation du code :
1
2
3
4
void f()
{
cout << a << endl;
}
// a n’a pas été déclarée
5
6
7
8
9
10
11
1
2
3
int main()
{
int a = 12; // a est une variable locale du main()
f();
return 0;
}
produira l’erreur
mp.cpp:410:11: error: use of undeclared identifier ’a’; did you mean ’std::uniform_int_distribution<long>::a’?
cout << a << endl;
// a une variable locale à f()
car, même si la variable a existe durant toute l’exécution du programme, elle est locale à la fonction
main et ne peut donc être utilisée ailleurs que dans cette fonction.
Le fait que les variables soient locales à des fonctions explique l’utilisation des paramètres
et valeur de retour. En effet, une fonction ne peut communiquer des données avec son
programme appelant qu’avec ces paramètres et valeur de retour.
I Sur ce thème : Exercice 1, questions 1.17 et 1.18, TD 5
4.2
Transmission des paramètres
Il existe deux façons de passer des arguments à une fonction changeant la manière dont les
modifications des paramètres au sein de la fonction influent dans le reste du programme.
1er semestre
71 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
4.2.1
Passage par copie (ou par valeur)
Lors de l’appel d’une fonction, lorsqu’une variable est passée en paramètre, une copie est créée,
qui correspond au paramètre. Le nom de la variable est local à la fonction à laquelle il appartient,
par conséquent une variable x de la fonction appelante n’est pas la même (zone mémoire) que la
variable x de la fonction appelée.
Exemple. Soit le programme suivant :
1
2
3
4
5
6
void change(int i)
{
cout << "i = " << i << endl;
i = 3;
cout << "i = " << i << endl;
}
7
8
9
10
11
12
13
14
15
16
int main()
{
int i;
i = 5;
cout << "i = " << i << endl;
change(i);
cout << "i = " << i << endl;
return 0;
}
i
(main)
i
(main)
i
(change)
5
5
5
(a) Après exécution de la ligne 11
i
(main)
i
(change)
5
3
(b) Avant exécution de la ligne 4
i
(main)
5
(d) Après exécution de la ligne 13
(c) Après exécution de la ligne 4
Figure 4.2 – Passage d’un paramètre par valeur
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 4.2(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 de la variable i par copie. Une copie de la variable est
donc créée en mémoire et affectée au paramètre de la fonction change (qui s’appelle également i).
L’état de la mémoire correspond à celui indiqué dans la figure 4.2(b). L’instruction ligne 3 affiche
donc i=5. Puis, la valeur de i est changée ligne 4. Une seule variable i est connue de la fonction
change, et c’est par conséquent celle-là qui est modifiée (voir figure 4.2(c)). La ligne 5 affiche alors
i=3. À ce moment-là, l’exécution de change est terminée et les variables associées libérées. Alors,
après l’exécution de la ligne 13, la mémoire est dans le même état qu’avant cet appel, comme
décrit par la figure 4.2(d). La ligne 14 affiche donc i=5.
4.2.2
Passage par référence
Ceci sera l’objet d’un autre cours.
Intro à l’algorithmique et à la programmation
72 1er semestre
Departement informatique
I Sur ce thème : Exercices 4, TD 5
I Sur ce thème : Exercices 5, TD 5
4.3
Création de fonctions
Lorsque l’on doit définir une fonction, il faut d’abord déterminer les paramètres, leur type, leur
mode de passage et la valeur de retour avant de commencer à écrire le corps de la fonction. La
création d’une fonction doit donc se faire en plusieurs étapes expliquées dans cette partie.
4.3.1
Commentaire d’une fonction
Une fonction ayant pour but d’être réutilisée, il est nécessaire de bien la commenter. Pour cela,
le commentaire de la fonction doit être écrit juste avant l’en-tête de la fonction et doit respecter
certaines conventions. Ce commentaire sert à expliquer la fonction. Il doit indiquer à quoi sert la
fonction, quels sont les paramètres et les types attendus, ainsi que la valeur de retour. Voici un
exemple de commentaire de fonction :
1
2
3
4
5
6
7
8
9
10
/*!
* Fonction affichant "bonjour X" où X est le nom passé en argument.
* Cette fonction ne retourne aucune valeur.
*
* \param s : nom à afficher après bonjour
*/
void bonjour (string s)
{
cout << "bonjour " << s << endl;
}
Par la suite, nous utiliserons systématiquement cette convention (en utilisant \param
pour les paramètres).
Le commentaire de fonction, s’il est bien écrit, permet à tout codeur d’utiliser correctement
n’importe quelle fonction définie (par vous ou par un autre) sans avoir à regarder le code de
la fonction. De plus, avec la convention que l’on utilise, il est possible, avec le logiciel doxygen,
de construire automatiquement un document html présentant le code commenté de tout un programme C++.
4.3.2
Étapes lors de la création de fonctions
Il est très important, lors de la définition d’une fonction, de déterminer les arguments nécessaires à une fonction, ainsi que la valeur de retour. (Attention à ne pas confondre paramètres
et variables locales.) De plus, il faut choisir le mode de passage des paramètres (par copie ou
par référence). Seuls les paramètres correspondant à une sortie (valeur calculée par la
fonction) doivent être passés par référence (ce type de passage de paramètres sera abordée
dans un prochain cours). Avant de penser à écrire le corps de la fonction, il faut impérativement
réfléchir aux informations qui sont nécessaires pour effectuer le traitement. La définition d’une
fonction doit se faire en plusieurs étapes :
1. Que doit réellement faire cette fonction ?
2. Comment nommer la fonction ? Quels sont ses paramètres ? Lesquels sont passés par copie,
par référence ? (pour l’instant nous avons abordé que le transfert par valeur) Quelle est la
valeur retournée ? Quels sont les types des paramètres et de la valeur retournée ? Qu’écrit-on
comme en-tête de fonction ? Comme commentaire de fonction ?
3. Comment appeler cette fonction dans le code ? Donner un ou plusieurs exemple(s) d’appels.
4. Écrire le corps de la fonction.
1er semestre
73 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
Il est inutile de commencer à écrire le corps de la fonction si les trois premières étapes n’ont
pas été faites (ou du moins mûrement réfléchies).
4.3.3
Exemple de création d’une fonction
On illustre la création de fonctions à l’aide d’un exemple. Une des interactions les plus courantes
avec l’utilisateur consiste à lui demander confirmation d’une proposition (répondre par oui ou par
non) et à contrôler que sa réponse est bien une des réponses attendues. C’est si fréquent que cela
vaut la peine d’en faire une fonction.
Étape 1 La fonction doit permettre à l’utilisateur de confirmer ou d’infirmer une proposition.
La fonction va donc devoir afficher un message puis lire la réponse saisie par l’utilisateur. Bien que
cette fonction soit extrêmement simple, elle soulève plusieurs questions :
– Quelles sont les réponses possibles ? Comme on suppose que le programme est écrit en
français, on choisit alors d’admettre comme réponses possibles : "oui", "non", "o", "n".
De plus, les réponses peuvent être écrites avec des lettres minuscules et/ou majuscules.
– Que se passe-t-il si l’utilisateur ne saisit pas une des réponses permises ? On décide alors que
l’on répète la saisie jusqu’à obtenir une réponse admissible.
Étape 2 Il faut alors répondre aux questions :
– Comment nommer la fonction ? On peut nommer cette fonction confirmation.
– Quels sont ses paramètres ? Lesquels sont passés par copie, par référence ? Quelle est la
valeur retournée ? Quels sont les types des paramètres et de la valeur retournée ? Comme
la saisie est faite à l’intérieur de la fonction, il n’y a pas besoin d’entrée. Il faut par contre
que la fonction transmette la réponse de l’utilisateur, à savoir s’il confirme ou non. On
peut donc alors décider qu’il n’y a aucun paramètre et une valeur retournée. Comme la
valeur retournée n’admet que deux réponses (l’utilisateur confirme ou infirme), on peut donc
renvoyer un booléen.
– Qu’écrit-on comme en-tête de fonction ? Comme commentaire de fonction ?
1
2
3
4
5
6
7
8
9
/*!
* Fonction permettant à l’utilisateur de confirmer ou d’infirmer une proposition.
* La saisie est répétée jusqu’à ce que l’utilisateur saisisse une des réponses permises :
* "oui", "non", "o", "n", (majuscules et/ou minuscules)
*
* La fonction renvoie un booléen égal à true si l’utilisateur a confirmé, false sinon.
*/
bool confirmation ()
{
//Corps de la fonction
10
11
}
Étape 3 Voici un exemple d’appel de la fonction confirmation :
1
2
3
4
5
6
7
8
9
int main()
{
cout << "La terre est-elle ronde ?" << endl;
if (confirmation())
cout << "Bravo" << endl;
else
cout << "Il faut revoir les bases de l’astronomie..." << endl;
return 0;
}
Intro à l’algorithmique et à la programmation
74 1er semestre
Departement informatique
Étape 4 Corps de la fonction :
1
2
3
4
5
6
7
8
9
bool confirmation()
{
string rep = "";
while (rep!= "oui" && rep != "o" && rep != "non" && rep != "n")
{
cout << "Répondez par oui ou par non (o/n) :";
saisie(rep);
rep = lower(rep); //On met la réponse en minuscules
}
10
if (rep=="oui" || rep=="o")
return true;
return false;
11
12
13
14
}
I Sur ce thème : Exercices 8 à 7, TD 5
I Sur ce thème : Exercices 8 à 7, TD 5
I Sur ce thème : Exercices 8 à 7, TD 5
1er semestre
75 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
TD4 : Fonctions (Corrigé)
X Exercice 1 : Test de compréhension*
Question 1.1 : [Définition et appel] Quelle est la différence entre définition d’une fonction et
appel d’une fonction ?
Correction :
– Définition : on donne l’en-tête de la fonction et le corps de la fonction (aucune instruction n’est exécutée).
– Appel : les instructions associées à la fonction sont exécutées pour certaines valeurs données entre parenthèses.
3
Question 1.2 : [En-tête et corps] Qu’est-ce que l’en-tête d’une fonction ? Le corps d’une fonction ?
Correction :
– En-tête : première ligne contenant le type de retour, le nom de la fonction, les paramètres (entre parenthèses
séparés par des virgules) ainsi que leur type.
– Corps : les instructions associées à la fonction.
3
Question 1.3 : [Paramètres et valeurs des paramètres] Quelle est la différence entre paramètres
et valeurs des paramètres ?
Correction :
– Paramètres : noms donnés entre parenthèses de l’en-tête de la fonction. Les paramètres n’ont pas de valeur
et sont utilisées dans le corps de la fonction pour expliquer les instructions.
– Valeurs des paramètres : les valeurs passées à la fonction lors d’un appel.
3
Question 1.4 : [Programme appelant] Qu’est-ce qu’un programme appelant pour une fonction ?
Correction :
Partie de code où la fonction est appelée (exécutée). Le programme appelant peut être le programme principal ou
une fonction. (Il peut y avoir plusieurs programmes appelants.)
3
Question 1.5 : [Parenthèses] Les parenthèses sont-elles obligatoires dans la définition d’une fonction s’il n’y a pas d’arguments ? Sont-elles nécessaires dans un appel de fonction s’il n’y a pas de
valeurs d’arguments ?
Correction :
Oui, les parenthèses sont nécessaires dans les deux cas pour indiquer à l’ordinateur que l’on définit ou que l’on
appelle une fonction.
3
Question 1.6 : [Nombre d’appels] Combien de fois une fonction peut-elle être appelée au minimum ? Au maximum ? Donner deux exemples où une fonction est appelée 100 fois, un avec
les mêmes valeurs d’arguments pour tous les appels, puis l’autre avec des valeurs d’arguments
différents à chaque appel.
Correction :
Une fonction peut être appelée 0 fois au minimum. Il n’y a pas de limite maximum (Par exemple une boucle infinie
appelant à chaque itération une fonction). Exemples avec la fonction int2string() :
1
2
3
int foisDeux(int n){
return 2*n;
}
4
5
6
//Meme valeur d’argument
7
int accumulateur = 0;
int i = 0;
8
Intro à l’algorithmique et à la programmation
76 1er semestre
Departement informatique
9
10
11
12
13
while (i<100)
{
accumulateur += foisDeux(1);
i++;
}
14
15
//Avec des valeurs d’argument différents
16
int accumulateur = 0;
int i = 0;
while (i<100)
{
accumulateur += foisDeux(i);
i++;
}
17
18
19
20
21
22
3 Question 1.7 : [Définition et appel] Considérons le code suivant :
1
2
3
4
void afficheRes(int nb)
{
cout << "Le résultat est " << nb << endl;
}
5
6
7
8
9
10
void somme2nb(int a, int b)
{
cout << "Premier nombre = " << a << ", deuxième nombre = " << b << endl;
afficheRes(a+b);
}
11
12
13
14
15
16
int main()
{
somme2nb(1,2);
return 0;
}
Donner, pour la fonction somme2nb, les numéros des lignes associées à l’en-tête, au corps de la
fonction, à la définition et à l’appel de la fonction. Indiquer également le programme appelant.
Donner finalement ses arguments et ses valeurs d’arguments lors de son appel. Répondre ensuite
aux mêmes questions pour la fonction afficheRes.
Correction :
– Fonction somme2nb :
– En-tête : ligne 6
– Corps : lignes 8-9
– Définition : lignes 6-10
– Appel : ligne 14
– Programme appelant : programme principal (fonction main)
– 2 arguments a et b de type int. Valeurs des arguments lors de l’appel : 1 et 2.
– Fonction afficheRes() :
– En-tête : ligne 1
– Corps : ligne 3
– Définition : lignes 1-4
– Appel : ligne 9
– Programme appelant : fonction somme2nb
– 1 argument nb. Valeur d’argument lors de l’appel : 3 (1+2).
3
Question 1.8 : [Exécution de code (1)] Considérons le code :
1
2
void f1()
{
1er semestre
77 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
cout << "hello" << endl;
cout << "hello" << endl;
3
4
5
}
6
7
8
9
10
11
int main()
{
cout << "hello" << endl;
return 0;
}
Lors de l’exécution de ce code, combien de fois la fonction f1 est-elle appelée ? Combien de fois
est affiché hello ?
Correction :
La fonction f1 n’est jamais appelée. hello est donc affiché une seule fois.
3
Question 1.9 : [Exécution de code (2)] Considérons le code :
1
2
3
4
5
void f2()
{
cout << "hello" << endl;
cout << "hello" << endl;
}
6
7
8
9
10
11
12
13
int main()
{
cout << "hello" << endl;
f2();
f2();
return 0;
}
Lors de l’exécution de ce code, combien de fois la fonction f2 est-elle appelée ? Combien de fois
est affiché hello ?
Correction :
La fonction f2 est appelée 2 fois. hello est donc affiché 5 fois.
3
Question 1.10 : [Exécution de code (3)] Considérons le code :
1
2
3
4
5
void f3()
{
cout << "hello" << endl;
cout << "hello" << endl;
}
6
7
8
9
10
11
12
void f4()
{
f3();
cout << "hello" << endl;
f3();
}
13
14
15
16
17
18
19
20
int main()
{
cout << "hello" << endl;
f3();
f4();
return 0;
}
Intro à l’algorithmique et à la programmation
78 1er semestre
Departement informatique
Lors de l’exécution de ce code, combien de fois sont appelées f3 et f4 ? Combien de fois est affiché
hello ?
Correction :
f4 est appelée 1 fois et f3 3 fois. hello est donc affichée 8 fois.
3
Question 1.11 : [Exécution de code (4)] Considérons le code :
1
2
3
4
5
void f5()
{
cout << "hello" << endl;
cout << "hello" << endl;
}
6
7
8
9
10
11
12
13
14
15
16
void f6(int n)
{
int i = 0;
while (i<n)
{
f5();
i++;
}
cout << "hello" << endl;
}
17
18
19
20
21
22
23
24
25
int main()
{
cout << "hello" << endl;
f5();
f6(2);
f6(4);
return 0;
}
Lors de l’exécution de ce code, combien de fois sont appelées f5() et f6() ? Combien de fois est
affiché hello ?
Correction :
f6 est appelée 2 fois et f5 7 fois. hello est affichée 17 fois.
3
Question 1.12 : [Valeur d’arguments (1)] Considérons le code :
1
2
3
4
void f(int a)
{
cout << "a = " << a << endl;
}
5
6
7
8
9
10
11
12
13
int main()
{
int a = 3;
int b = 5;
a = 18;
f(b);
return 0;
}
Quel est l’affichage produit par l’exécution du code précédent ?
Correction :
3
a = 5
1er semestre
79 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
Question 1.13 : [Valeur d’arguments (2)] Quel affichage donne l’exécution du code :
1
2
3
4
void f(int a, int b)
{
cout << "a = " << a << ", b = " << b << endl;
}
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
int main()
{
int a = 3;
int b = 4;
f(a,b);
f(b,a);
f(a,a);
f(b+2,b-3);
return 0;
}
Correction :
a
a
a
a
=
=
=
=
3,
4,
3,
6,
b
b
b
b
=
=
=
=
4
3
3
1
3 Question 1.14 : [Valeur retournée par une fonction (1)] Lors de l’exécution de ce code, combien
de fois est appelée f ? Combien de fois est affiché hello ?
1
2
3
4
5
6
void f(int a)
{
if (a<0)
return;
cout << "hello" << endl;
}
7
8
9
10
11
12
13
int main()
{
f(3);
f(-2);
return 0;
}
Correction :
La fonction f est appelée 2 fois et hello est affichée une seule fois.
3
Question 1.15 : [Valeur retournée par une fonction (2)] Lors de l’exécution du code suivant, quel
est l’affichage produit ? Quelles sont les valeurs des variables ?
1
2
3
4
int f(int x)
{
return 2 * x + 3;
}
5
6
7
8
int main()
{
int res = f(3);
Intro à l’algorithmique et à la programmation
80 1er semestre
Departement informatique
cout << res <<
int z = 2;
res = f(z);
cout << res <<
cout << f(res)
res = f(res);
cout << res <<
cout << f(res)
return 0;
9
10
11
12
13
14
15
16
17
18
endl;
endl;
<< endl;
endl;
<< endl;
}
Affichage :
Correction :
1
2
3
4
5
9
7
17
17
37
3
La variable z a la valeur 2, res a la valeur 17.
Question 1.16 : [Valeur retournée par une fonction (3)] Considérons les fonctions somme1 et
somme2 définies par :
1
2
3
4
void somme1(int a, int b)
{
cout << a+b << endl;
}
5
6
7
8
9
int somme2(int a, int b)
{
return a+b;
}
1. Quelle est la différence entre somme1 et somme2 ? Donner le commentaire associé à chacune
des deux fonctions.
2. Utiliser la fonction somme1 pour afficher le résultat de 2 + 7 (sans utiliser l’opérateur +).
Même question avec la fonction somme2.
3. Utiliser la fonction somme1 pour afficher le résultat de 2 + 7 + 18 (sans utiliser l’opérateur +).
Même question avec la fonction somme2. Quelle est alors la fonction la mieux programmée ?
Correction :
1. somme1 prend deux paramètres et ne retourne aucune valeur. Elle affiche le résultat de l’opération +. somme2
prend deux paramètres et retourne le résultat de l’opération +.
2. 1
2
somme1(2,7);
cout << somme2(2,7) << endl;
3. Ce n’est pas possible de faire un calcul (autre qu’une addition) avec somme1.
Avec somme2 : cout « somme2(somme2(2,7),18) « endl;. On en déduit que la fonction somme2 est mieux
programmée puisqu’elle est plus générique.
3
Question 1.17 : [Portée des variables] Considérons le code :
1
2
3
void f()
1er semestre
81 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
4
{
int a = 18;
cout << "a = " << a << endl;
5
6
7
}
8
9
10
11
12
13
14
15
1
2
int main()
{
int a = 5;
f();
cout << "a = " << a << endl;
return 0;
}
Quel est l’affichage produit par l’exécution du code précédent ?
Correction :
a = 18
a = 5
3 Question 1.18 : [Paramètres et variables locales] Considérons le code :
1
2
3
4
5
6
void f(int a)
{
int a = 10;
a +=1;
cout << "a = " << a << endl;
}
7
8
9
10
11
12
13
1
2
int main()
{
f(3);
f(6);
return 0;
}
Quel est l’affichage produit par l’exécution du code précédent ? Ne peut-on pas améliorer le code ?
Correction :
a = 11
a = 11
Il y a un problème lors de la conception de la fonction f(). En effet, cette fonction prend un paramètre mais sa
valeur n’est jamais utilisée. Ce n’est donc pas un paramètre mais une variable locale. Certains compilateurs peuvent
même considérer ceci comme une erreur de compilation. Il faut donc simplifier le code en supprimant le paramètre.
1
2
3
4
5
void f()
{
int varLocale = 11;
cout << "a = " << varLocale << endl;
}
3 r Exercice 2 : Comparer deux nombres
Écrire la fonction compare qui reçoit deux nombres entiers en argument a et b et affiche un
message adapté selon que a est supérieur, inférieur ou égal à à b.
Correction :
Intro à l’algorithmique et à la programmation
82 1er semestre
Departement informatique
1
2
3
4
5
6
7
8
9
void compare(int a, int b)
{
if (a==b)
cout << a << " est égal à " << b << endl;
else if (a < b)
cout << a << " est inférieur à " << b << endl;
else
cout << a << " est supérieur à " << b << endl;
}
10
11
12
13
14
15
int main()
{
compare(12,18);
return 0;
}
3
r Exercice 3 : Test de parité
Question 3.1 : Écrire la fonction estPair qui affiche si un nombre reçu en paramètre est pair
ou non.
Correction :
1
2
3
4
5
6
7
void estPair(int nombre)
{
if (nombre%2)
cout << "Le nombre " << nombre << " est pair." << endl;
else
cout << "Le nombre " << nombre << " est impair." << endl;
}
3
Question 3.2 : Ré-écrire la fonction estPair() pour que cette dernière renvoie true si le nombre
reçu en paramètre est pair, false sinon.
Correction :
1
2
3
4
5
6
bool estPair(int nombre)
{
return nombre%2==0;
}
7
8
9
10
11
12
13
14
15
int main()
{
if (estPair(12))
cout << "12 est pair" << endl;
else
cout << "12 est impair" << endl;
return 0;
}
3
X Exercice 4 : Moyenne de deux nombres*
1er semestre
83 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
Écrire la fonction qui reçoit deux nombres flottants en argument et qui calcule et renvoie leur
moyenne. Que se passe-t-il si l’on souhaite faire la moyenne de 2 et de 3 ?
Correction :
1
2
3
4
double moyenne(double a, double b)
{
return (a+b)/2;
}
5
6
7
8
9
10
int main()
{
cout << "Moyenne de 2 et 3 = " << moyenne(2,3) << endl;
return 0;
}
Il n’y a aucun problème pour faire la moyenne de deux entiers car comme les paramètres sont spécifiés comme étant
de type double, les valeurs 2 et 3 sont implicitement convertis en 2.0 et 3.0 respectivement. Dans tous les cas, (a+b)
est de type double et la division n’est pas une division entière (le dénominateur est automatiquement converti en
double).
3
X Exercice 5 : Année bissextile**
Écrire une fonction qui permet de determiner si une année est bissextile. On rappelle qu’une
année est bissextile si
– elle est divisible par 4
– mais n’est pas divible par 100
– sauf si elle est divisible par 400
Ainsi 2008 était bissextile, 1900 n’était pas bissextile et 2000 était bissextile.
Correction :
1
2
3
4
5
6
bool estBissextile(int annee)
{
if (annee%4==0 && (annee%100!=0 || annee%400==0))
return true;
return false;
}
3 X Exercice 6 : En-tête et commentaire de fonctions*
Pour chaque cas, donner l’en-tête et le commentaire de la fonction demandée. Donner également, lorsque c’est possible, deux appels de la fonction avec des valeurs de paramètres différents.
1. Fonction calculant la valeur absolue d’un nombre
Correction :
1
2
3
4
5
6
7
8
9
/*!
* \fn double absolue(double nb)
*
* Fonction retournant la valeur absolue d’un nombre
*
* \param nb : nombre dont on veut la valeur absolue
*
* La fonction renvoie la valeur absolue de nb
*/
Exemple d’appel :
Intro à l’algorithmique et à la programmation
84 1er semestre
Departement informatique
1
cout << absolue(-49.6) << endl; //Affiche 49.6
3
2. Fonction permettant la saisie d’un entier positif ou nul
Correction :
1
2
3
4
5
6
7
/*!
* \fn int saisiePosNul()
*
* Fonction retournant un entier positif ou nul saisi par l’utilisateur
*
* La fonction renvoie la valeur saisie par l’utilisateur
*/
Exemple d’appel :
1
int a = saisiePosNul();
3
3. Fonction permettant la saisie d’un entier compris dans un intervalle [a, b] (Par exemple, saisie
d’un entier entre 10 et 20).
Correction :
1
2
3
4
5
6
7
8
9
10
11
/*!
* \fn int saisieBornee(int a, int b)
*
* Fonction retournant un entier positif saisi par l’utilisateur compris entre a et b
*
* \param nb : borne inférieure de l’intervalle
*
* \param nb : borne supérieure de l’intervalle
*
* La fonction renvoie la valeur saisie par l’utilisateur
*/
Exemple d’appel :
1
int a = saisieBornee(10,20);
3
4. Fonction calculant la somme de deux fractions (par exemple la somme de 1/3 et 4/27)
Correction :
1
2
3
4
5
6
7
8
9
10
11
12
13
/*!
* \fn void sommeFractions(int num1, int den1, int num2, int den2, int &num_res, int &den_res)
*
* Fonction calculant la somme de deux fractions. Chaque fraction est codée avec deux entiers :
*
- un pour le numérateur
*
- un pour le dénominateur
*
* \param num1 : numérateur de la première fraction
* \param den1 : dénominateur de la première fraction
* \param num2 : numérateur de la deuxième fraction
* \param den2 : dénominateur de la deuxième fraction
* \param num1 : numérateur de la fraction résultat (valeur indéfinie en entrée)
* \param den1 : dénominateur de la fraction résultat (valeur indéfinie en entrée)
1er semestre
85 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
14
15
16
*
* La fonction ne renvoie rien
*/
Exemple d’appel :
1
2
3
int den,num;
sommeFractions(1, 2, 2, 3, num, den);
cout << "1/2 + 2/3 = " << num << "/" << den << endl;
3
5. Fonction permettant de remplacer dans une chaîne de caractères chaque occurence d’une
chaîne par une autre. Par exemple, le remplacement de "o" par "yoo" dans "bonjour"
(transformant "bonjour" en "byoonjyoour").
Correction :
1
2
3
4
5
6
7
8
9
10
11
/*!
* \fn void remplaceSousChaine(string &texte, string cible, string remplacement)
*
* Fonction remplaçant dans texte chaque occurence de cible par remplacement
*
* \param texte : chaîne dans laquelle on effectue les remplacements
* \param cible : portion de chaîne que l’on veut remplacer
* \param remplacement : chaîne qui remplace les occurences cibles trouvées
*
* La fonction ne renvoie rien
*/
Exemple d’appel :
1
2
3
string s = "bonjour";
remplaceSousChaine(s,"o","yoo");
cout << s << endl; //Affiche byoonjyoour
3
r Exercice 7 : Produit d’entiers**
Écrire une fonction produit qui calcule et renvoie le produit n1 ∗ (n1 + 1) ∗ ... ∗ n2 (1<=n1<=
n2 ) des entiers compris entre n1 et et n2 inclus.
Correction :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int produit(int n1, int n2)
{
if (n1>n2)
{
int tmp = n1;
n1 = n2;
n2 = tmp;
}
int produit = n1;
while (n2 > n1)
{
produit *= n2;
n2--;
}
return produit;
}
Intro à l’algorithmique et à la programmation
86 1er semestre
Departement informatique
Attention, le résultat peut très vite dépasser la capacité de stockage des int. Il vaut mieux déclarer la variable
produit et le retour de fonction comme unsigned long int voire comme double ou double suivant les valeurs des
paramètres que l’on veut tester.
3
1er semestre
87 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
TP4 : Fonction (Corrigé)
Exercice 8 : Définitions de fonctions et test dans un programme principal*
Pour chaque cas, définir la fonction demandée. Donner également un exemple d’appel de la
fonction dans un programme principal
1. Fonction calculant la valeur absolue d’un nombre
Correction :
1
2
3
4
5
6
7
double absolue(double nb)
{
double resultat=nb;
if (nb<0)
resultat*=1;
return resultat;
}
8
9
10
11
12
13
14
15
16
int main()
{
int nombre;
saisie(nombre);
cout<< "la valeur absolue de "<< nombre << " est "<< absolue(nombre)<< endl;
return 0;
}
3
2. Fonction permettant la saisie d’un entier positif ou nul et permettant d’effectuer des saisies
jusqu’à ce que ce nombre soit correct.
Correction :
1
2
3
int saisiePosNul()
{
int nb =-1;
4
while( nb < 0))
{
5
6
7
//saisie controlee d’un nombre positif ou nul
8
cout << "Saisir un nombre positif ou nul"<<endl;
saisie(nb);
9
}
return nb;
10
11
}
12
13
14
15
16
17
18
19
20
21
int main()
{
int nombre;
nombre=saisiePosNul();
cout<< nombre << " est positif ou nul "<< endl;
return 0;
}
Intro à l’algorithmique et à la programmation
3
88 1er semestre
Departement informatique
3. Fonction permettant la saisie d’un entier compris dans un intervalle [a, b] (Par exemple, saisie
d’un entier entre 10 et 20) et permettant d’effectuer des saisies jusqu’à ce que ce nombre soit
correct en indiquant à l’utilisateur s’il doit donner un nombre plus petit ou plus grand.
Correction :
1
2
3
int saisieBornee(int a, int b)
{
int nb;
4
//saisie controlee avec indications nombre compris entre a et b (inclus)
5
cout << "Saisir un nombre entre "<< a << " et "<< b <<" (inclus) "<<endl;
saisie(nb);
while( nb < a || nb > b)
{
if (nb<a)
cout<< "Plus grand !" <<endl;
else
cout<< "Plus petit !" <<endl;
cout << "Saisir un nombre entre "<< a << " et "<< b <<" (inclus) "<<endl;
saisie(nb);
}
return nb;
6
7
8
9
10
11
12
13
14
15
16
}
17
18
19
20
21
22
23
24
25
int main()
{
int nombre;
nombre=saisieBornee(10,20);
cout<< nombre << " est dans le bon intervalle "<< endl;
return 0;
}
3 Exercice 9 : Calcul de xn quand n est un entier positif ou nul*
Écrire une fonction permettant de calcul xn quand n est un entier positif. Tester cette fonction
en l’appelant dans un programme principal
Correction :
1
2
3
4
5
6
7
8
9
10
11
double puissance(double x, int n)
{
double resultat=1;
int compteur =n;
while(compteur>0)
{
resultat *= x;
compteur--;
}
return resultat;
}
12
13
14
15
16
int main()
{
double nb;
int p;
17
18
19
20
21
cout<<"Donner un nombre \n";
saisie(nb);
cout<<"Donner une puissance \n";
saisie(p);
1er semestre
89 Intro à l’algorithmique et à la programmation
IUT de Villetaneuse
cout<< nb << " puissance "<< p <<" = "<< puissance(nb,p)<<endl;
return 0;
22
23
24
}
3 Exercice 10 : Discriminant d’un polynôme de second degrès*
Le but de cet exercice est de créer une fonction permettant de calculer et retourner la valeur
du discriminant d’un polynôme de second degrés :a*x*x + b*x + c = 0.
Rappel : d = b*b-4*a*c où d est le discriminant.
Travail à faire :
– Écrire cette fonction,
– Écrire un programme de tests permettant d’afficher un message clair suivant la valeur du
discriminant calculé : "Pas de racines réelles", "Racine double réelle", etc.
Correction :
1
10
/*!
* Fonction retournant la valeur du discriminant du polynome a*x*x + b *x + c = 0
*
* \param a : coefficient de second degré
* \param b : coefficient de premier degré
* \param c : constante de l’équation
*
* La fonction renvoie la valeur du discriminant
*/
11
double discriminantPlySecondDegre (int a, int b, int c){
2
3
4
5
6
7
8
9
12
return b*b-4*a*c;
13
14
}
1
2
3
Exemple d’appel de la fonction discriminantPlySecondDegre :
int main()
{
double discriminant = discriminantPlySecondDegre (1,2, -3);
4
if (discriminant>0)
cout << "Deux racines réelles" << endl;
else if (discriminant==0)
cout << "Racine réelle double" << endl;
else
cout << "Aucune solution réelle " << endl;
5
6
7
8
9
10
11
return 0;
12
13
}
3 Exercice 11 : Calcul du PGCD**
L’algorithme d’Euclide calculant le plus grand diviseur commun (pgcd ) de deux nombres entiers
peut être décrit comme suit : "tant que les 2 nombres sont différents soustraire le plus petit du
plus grand. Une fois égaux, afficher l’un d’eux : c’est le pgcd."
1. faire tourner cet algorithme sur papier avec les entiers 18 et 14,
2. écrire la fonction qui calcule et retourne le pgcd de deux arguments entiers,
Intro à l’algorithmique et à la programmation
90 1er semestre
Departement informatique
3. écrire un programme appelant permettant de tester la fonction développée.
Correction :
1. réponse à la question 1
n1 = 18
n2 = 14
n2<n1 donc n1=n1-n2 n1 = 4
n1<n2 donc n2=n2-n1 n2 = 10
n1<n2 donc n2=n2-n1 n2 = 6
n1<n2 donc n2=n2-n1 n2 = 2
n2<n1 donc n1 = n1-n2 n1 = 2
n1 = n2 donc pgcd = 2pgcd
2. réponse à la question 2
1
2
3
4
5
6
7
8
9
10
11
int pgcd(int n1, int n2){
while (n1 != n2){
if (n1>n2){
n1 = n1-n2;
}
else if (n2>n1){
n2 = n2-n1;
}
}
return n1;
}
12
13
//test de la fonction pgcd
14
int main(){
int a = 4;
int b = 10;
15
16
17
int res = pgcd(a, b);
18
19
cout<<"Le pgcd de " << a << " et de " << b << " est " << res<<endl;
20
21
return 0;
22
23
}
Affichage obtenu :
Le pgcd de 4 et de 10 est 2
1er semestre
3
91 Intro à l’algorithmique et à la programmation