Correction 5
Fonctions (1)
Par ailleurs, les solutions proposées correspondent à l'état de vos connaissances au moment où la série est abordée. D'autres solutions pourront être envisagées une fois de nouveaux concepts acquis.
| Exercice 1 | Exercice 2 | Exercice 3 | Exercice 4 | Exercice 5 | Exercice 6 | Exercice 7 |
Exercice 1 : Portée (niveau 1)
#include <iostream>
using namespace std;
int variable(10); // ceci est une variable globale
int main()
{
{ // ici nous avons un nouveau bloc : disons bloc1
int variable(5); // variable locale à bloc1
cout << "Un, la variable vaut : " << variable << endl; // affiche 5
}
{ /* ici nous avons un nouveau bloc : bloc2
* mais il ne definit pas de variable "variable"
* L'appel ci-dessous fait donc appel à la variable globale
*/
cout << "Deux, la variable vaut : " << variable << endl; // affiche 10
}
// ici un bloc "for" avec une variable locale au bloc
for (int variable(0); variable < 3; ++variable) {
cout << "Trois, la variable vaut : " << variable << endl; // affiche 0, 1, 2
}
/* encore la variable globale car aucune variable "variable"
* n'est définie au niveau de ce bloc (main())
*/
cout << "Quatre, la variable vaut : " << variable << endl; // affiche 10
/* ici un autre bloc "for", mais attention il NE déclare PAS la
* variable "variable" (c'est ici une affectation, pas une
* déclaration) et donc il utilise la variable GLOBALE
*/
for (variable = 0; variable < 3; ++variable) {
cout << "Cinq, la variable vaut : " << variable << endl; // affiche 0, 1, 2
}
/* c'est toujours la variable GLOBALE dont il s'agit ici mais
* elle a été modifiée par le for précédent et sa valeur est donc 3,
* la valeur qui a fait sortir du "for".
*/
cout << "Six, la variable vaut : " << variable << endl; // affiche 3
return 0;
}
Exercice 2 : Prototypes (niveau 1, puis 2 pour le point 5)
Solution de 1,2,3 :
La fonction demander_nombre() ne prend aucun paramètre puisqu'elle se contente de demander un entier à l'utilisateur (elle n'a donc besoin de rien !). Par contre elle devra retourner la valeur saisie par l'utilisateur. Le type de la valeur retournée par la fonction devant être spécifié dans le prototype, celui-ci est donc int demander_nombre();.
L'écriture du corps de la fonction ne présente rien de nouveau : on déclare une variable entière a_retourner, on l'affecte à la valeur entrée par l'utilisateur, puis on retourne cette valeur à l'aide de l'instruction return.
Afin de pouvoir être utilisée dans la fonction main(), la fonction doit avoir été prototypée avant. Sa définition peut ensuite être placée n'importe où après le prototype). La valeur retournée par la demander_nombre() peut être assignée à la variable num de la fonction main() avec l'instruction num = demander_nombre();.
Voici le code complet de la première partie de l'exercice :
#include <iostream>
using namespace std;
int demander_nombre();
int main()
{
int num;
num = demander_nombre();
cout << "Le nombre est : " << num << endl;
return 0;
}
int demander_nombre()
{
int res;
cout << "Entrez un nombre entier : ";
cin >> res;
return res;
}
Solution de 4 :
#include <iostream>
using namespace std;
int demander_nombre(int min, int max);
int main()
{
int num;
num = demander_nombre(1, 100);
cout << "Le nombre est : " << num << endl;
return 0;
}
int demander_nombre(int a, int b)
{
// échange a et b si ils ne sont pas dans le bon ordre
// ceci est NÉCESSAIRE si on ne veut pas de boucle infinie
// dans le cas ou on appelle la fonction avec a>b !!
if (a > b) { int tmp(b); b=a; a=tmp; }
int res;
do {
cout << "Entrez un nombre entier compris entre "
<< a << " et " << b <<" : ";
cin >> res;
} while ((res < a) or (res > b));
return res;
}
Solution de 5 :
#include <iostream>
using namespace std;
int demander_nombre(int min, int max);
int main()
{
int num;
num = demander_nombre (1, 100);
cout << "Le nombre est : " << num << endl;
num = demander_nombre (100, 1);
cout << "Le nombre est : " << num << endl;
return 0;
}
int demander_nombre(int a, int b)
{
int res;
do {
cout << "Entrez un nombre entier ";
if (a >= b)
cout << "supérieur ou égal à " << a;
else
cout << "compris entre " << a << " et " << b;
cout << " : ";
cin >> res;
} while ((res < a) or ((a < b) and (res > b)));
return res;
}
Exercice 3 : Fonctions simples
1)
double min2(double a, double b)
{
if (a < b) {
return a;
} else {
return b;
}
}
2) Sans utiliser min2 :
double min3(double a, double b, double c)
{
if (a < b) {
if (a < c) {
return a;
} else {
return c;
}
} else {
if (c < b) {
return c;
} else {
return b;
}
}
}
Pour calculer le minimum de 3 nombres, on peut aussi calculer d'abord le minimum des 2 premiers, et ensuite calculer le minimum de ce résultat et du dernier nombre, ce qui permet de réutiliser min2 :
double min3(double a, double b, double c)
{
return min2(min2(a, b), c);
}
Exercice 4 : Passage des paramètres (niveau 1)
Le code de la fonction main() nous donne des indications sur le fonctionnement de la fonction echange :
- La valeur de retour de la fonction n'est assignée à aucune variable. Le type de la valeur de retour de la fonction est donc void.
- Les variables i et j passées en paramètre à la fonction sont de type int.
- Les valeurs des paramètres sont échangées bien que les variables soient locales à la fonction main(), i.e. hors de portée de la fonction echange. Les paramètres doivent donc être passés par référence.
Nous pouvons donc maintenant écrire le prototype de la fonction :
void echange(int& a, int& b);
La définition de la fonction peut maintenant échanger les valeurs en utilisant une variable intermédiaire du même type pour stocker temporairement l'une des valeurs :
void echange(int& a, int& b)
{
int copie(a);
a=b;
b=copie;
}
Exercice 5 : Sapin
#include <iostream>
using namespace std;
void etoiles(int nb_etoiles)
{
for(int i(0); i < nb_etoiles; ++i) {
cout << "*";
}
}
void espaces(int nb_espaces)
{
for(int i(0); i < nb_espaces; ++i) {
cout << " ";
}
}
void triangle(int nb_lignes)
{
for(int i(0); i < nb_lignes; ++i) {
espaces(nb_lignes - i);
etoiles(2 * i + 1);
cout << endl;
}
}
void triangle_decale(int nb_lignes, int nb_espaces)
{
for(int i(0); i < nb_lignes; ++i) {
espaces(nb_espaces + nb_lignes - i);
etoiles(2 * i + 1);
cout << endl;
}
}
void sapin()
{
triangle_decale(2, 2);
triangle_decale(3, 1);
triangle_decale(4, 0);
// le tronc:
triangle_decale(1, 3);
}
/* Cette fonction permet d'afficher les 3 parties du beau sapin.
* no_ligne_fin a le meme role que le parametre nb_lignes
* des fonctions triangle et triangle_decale.
* no_ligne_debut definit la ligne du haut du trapeze.
*/
void trapeze_decale(int no_ligne_debut, int no_ligne_fin, int nb_espaces)
{
for(int i(no_ligne_debut); i < no_ligne_fin; ++i) {
espaces(nb_espaces + no_ligne_fin - i);
etoiles(2 * i + 1);
cout << endl;
}
}
void beau_sapin()
{
trapeze_decale(0, 3, 2);
trapeze_decale(1, 4, 1);
trapeze_decale(2, 5, 0);
cout << " |||" << endl;
}
/* Cette fonction n'etait pas demandee.
* Notez qu'on peut avoir deux fonctions de meme nom, si leurs
* parametres sont differents
*/
void beau_sapin(int nb_etages)
{
for(int i(0); i < nb_etages; ++i) {
trapeze_decale(i, 3 + i, nb_etages - i);
}
espaces(2 + nb_etages);
cout << "|||" << endl;
}
int main()
{
beau_sapin(10);
return 0;
}
Exercice 6 : calcul de PGDC
Le début est assez classique
La nouveauté réside uniquement dans la fonction pgdc.
Sans surprise son prototype sera :
int pgdc(int a, int b);
La seule difficulté de cet exercice réside dans la bonne réalisation des calcul de ces suites x, y, u et v qui s'appelent les unes les autres.
Il faut faire particulièrement attention à l'ordre des calcul pour être sûr(e) d'utiliser les bonnes valeurs.
Avec l'aide de l'énoncé, on définit et initialise
int prev_u(1), prev_v(0), x(a), y(b), u(0), v(1),
new_u, new_v, q, r;
Le calcul peut alors se faire sans piège :
q = x/y;
r = x%y;
x = y;
y = r;
new_u = prev_u - q * u;
new_v = prev_v - q * v;
Mais il ne faut pas oublier de remettre à jour les valeurs servant à mémoriser :
prev_u = u;
u = new_u;
prev_v = v;
v = new_v;
On a donc finalement le programme suivant, avec en surligné les aspects plus avancés / les améliorations du programme, que vous pouvez donc supprimer dans une première correction :
#include <iostream>
#include <iomanip>
#include <string>
#include <cmath>
using namespace std;
int pgcd(int a, int b, bool verbose = false);
int demander_nombre(int min, int max);
int main()
{
char rep;
bool verbose;
do {
cout << "Verbose [o/n] ? " << flush;
cin >> rep;
} while ((rep != 'o') && (rep != 'n'));
verbose = (rep == 'o');
do {
int a(demander_nombre(1,0));
int b(demander_nombre(1,0));
cout << "PGCD(" << a << "," << b << ")=" << pgcd(a,b,verbose) << endl;
do {
cout << "Voulez-vous recommencer [o/n] ? " << flush;
cin >> rep;
} while ((rep != 'o') && (rep != 'n'));
} while (rep == 'o');
return 0;
}
// Definition de PCDG
int pgcd(int a, int b, bool verbose)
{
int prev_u(1), prev_v(0), x(a), y(b), u(0), v(1),
new_u, new_v, q, r;
if (verbose) {
cout << "Calcul du PGCD de " << a << " et " << b << endl;
cout << endl;
// Aspects avancés (vus plus tard)
// setw permet de dire sur quelle largeur va se faire
// l'affichage qui suit
cout << setw(10-int(log(double(a))/log(10.0))/2) << 'x'
<< setw(10) << 'y'
<< setw(10) << 'u'
<< setw(10) << 'v'
<< endl;
}
while (y != 0) {
q = x/y;
r = x%y;
new_u = prev_u - q * u;
new_v = prev_v - q * v;
// modification des variables pour
// la prochaine itération :
x = y;
y = r;
prev_u = u;
u = new_u;
prev_v = v;
v = new_v;
// aspects avancés (vus plus tard)
// pour formater joliment la sortie
if (verbose) {
cout << setw(10) << x
<< setw(10) << y
<< setw(10) << u
<< setw(10) << v
<< endl;
}
}
return x;
}
// --------------------------------------------------------------
// fonction demandant à l'utilisateur un nombre compris
// dans un intervalle [a, b], ou supérieur ou égal à a
// si b < a.
// Entrée : les deux nombres a et b définissant l'intervalle
// Sortie : le nombre saisi par l'utilisateur
// --------------------------------------------------------------
int demander_nombre(int a, int b)
{
int res;
do {
cout << "Entrez un nombre entier ";
if (a >= b) {
cout << "supérieur ou égal à " << a;
}
else {
cout << "compris entre " << a << " et " << b;
}
cout << " : " << flush;
cin >> res;
// Aspects avancés : pour gérer les situations où les données
// introduites ne sont pas des entiers
if (cin.fail()) {
cout << "Je vous ai demandé d'entrer un nombre, "
<< "pas du charabia !" << endl;
cin.clear(); // remets cin dans un état lisible
string poubelle;
getline(cin, poubelle); // lit toute la ligne (pour la "jeter")
res = a-1;
}
} while ((res < a) || ((a < b) && (res > b)));
return res;
}
Exercice 7 : La fonction cosinus (définition et appel de fonction, niveau 2)
#include <iostream>
#include <cmath> // pour fmod et abs ; optionnel (pas demandé)
using namespace std;
double factorielle(int k);
double somme_partielle(double x, int N);
double somme_partielle2(double x, int N); // codage alternatif
double somme_partielle3(double x, int N); // codage alternatif
int demander_nombre(int a = 2, int b = 85);
int main()
{
int N(demander_nombre());
double x;
cout.precision(16);
do {
cout << "entrez une valeur x pour le calcul de cos(x) : ";
cin >> x;
x=fmod(abs(x), 2.0*M_PI); // optionnel : garantit que x est dans [0; 2pi]
cout << "cos(" << x << ") = ~ " << somme_partielle(x, N) << endl;
cout << "valeur calculée par la fonction C++ cos = " << cos(x) << std::endl;
} while (x != 0.0);
return 0;
}
double factorielle(int k)
{
double fact(1.0);
// k! = 1*2*..*k
for (int i(2); i <= k; ++i) {
fact *= i;
}
return fact;
}
double somme_partielle(double x, int N)
{
double current_approx(0.0); // approximation courante
double powerx(1.0); // puissance de x (initialisé à x^0=1)
for (int i(0); i <= N; ++i) {
double term(powerx / factorielle(i*2));
if (i%2 != 0) {
current_approx -= term;
} else {
current_approx += term;
}
powerx *= x*x; // powerx représente x^0, x^2, x^4, x^6, ..., x^2n
}
return current_approx;
}
// codage alternatif
double somme_partielle2(double x, int N)
{
double current_approx(0.0); // approximation courante
double powerx(1.0); // puissance de x (initialisé à x^0=1)
int mult_cste(1); // facteur multiplicatif
for (int i(0); i <= N*2; i+=2) { // calculer les N premiers membres de la
// somme revient à arriver au degré 2*N
double term(mult_cste * powerx / factorielle(i));
current_approx += term;
mult_cste *= -1;
powerx *= x*x; // powerx représente x^0, x^2, x^4, x^6, ..., x^2n
}
return current_approx;
}
// codage alternartif (mais l'appel à pow est plus coûteux que de simplement
// faire des multiplications (comme dans les codes précédents)
double somme_partielle3(double x, int N){
double approx(1.0);
for (int i(1); i <=N; ++i){
approx += (pow(-1,i)* pow(x,2*i))/factorielle(2*i);
}
return approx;
}
int demander_nombre(int a, int b)
{
int res;
if (a > b) { res=b; b=a; a=res; }
do {
cout << "Entrez le degré d'approximation (entre "
<< a << " et " << b <<") : ";
cin >> res;
} while ((res < a) or (res > b));
return res;
}
Dernière mise à jour : 2025/10/09 (17:28)