TD 3 : Structures de contrôles: instructions conditionnelles, boucles simples#
Notes aux enseignants
Ce TD/TP est essentiel : les conditionnelles et boucles sont des notions fondamentales, et difficiles pour certains.
Leur faire ouvrir leur poly à la page if, puis while.
Ne pas hésiter à demander d’abord le programme en français avant de l’écrire en C++.
De façon générale, quand on écrit du code au tableau, il est profitable de le prononcer en français en même temps (beaucoup d’élèves ne sont pas bons en anglais ne font pas l’association immédiate
if
-> si,while
-> tant que, etc.).
Dans les exercices suivants, vous préciserez le nom, l’entrée et la sortie de vos programmes. Par exemple, pour un programme calculant le maximum de deux nombres, vous écrirez :
// Programme maximum
// Entrée: deux entiers a et b de type int
// Sortie: le maximum de a et de b, stocké dans la variable max
int max;
if ( a >= b ) {
max = a;
} else {
max = b;
}
Si vous vous sentez à l’aise, mettez votre programme sous la forme d’une fonction :
int maximum(int a, int b) {
if ( a >= b ) {
return a;
} else {
return b;
}
}
Instructions conditionnelles: if
#
Exercice 1 :
Écrivez un programme qui prend en entrée l’âge d’une personne (un entier donc) et dont la sortie est
true
si la personne est majeure etfalse
sinon./// BEGIN SOLUTION
Solution naïve :
// Entrée: un entier age // Sortie: un booléen stocké dans la variable majeur, qui vaut // true si on est majeur, false sinon bool majeur; if ( age >= 18 ) { majeur = true; } else { majeur = false; }
Meilleure solution :
// Entrée: un entier age // Sortie: un booléen stocké dans la variable majeur, qui vaut // true si on est majeur, false sinon bool majeur = age >= 18;
/// END SOLUTION
Modifiez votre programme pour que la sortie soit une chaîne de caractères (type
string
) contenant le tarif SNCF appliqué à cette personne:"enfant"
(11 ans ou moins),"jeune"
(12-27 ans inclus),"senior"
(60 ans ou plus) ou"plein tarif"
sinon./// BEGIN SOLUTION
// Entrée : un entier age // Sortie : une chaîne de caractère stockée dans la variable tarif, // qui indique la catégorie de voyageur. string tarif; if (age < 11) { tarif = "enfant"; } else if (age >= 12 and age <= 27) { tarif = "jeune"; } else if (age > 60){ tarif = "senior"; } else { tarif = "plein tarif"; }
/// END SOLUTION
Exercice 2 : À faire chez vous
Le magasin Honeydukes est ouvert de 10h à 12h et de 14h à 19h. Écrivez un programme qui prend en entrée l’heure sous forme d’un entier et dont la sortie est
true
si le magasin est ouvert etfalse
sinon./// BEGIN SOLUTION
bool ouvert(int heure) { if ((heure >= 10 and heure <= 12) or (heure >= 14 and heure <= 19)) { return true; } else { return false; } }
/// END SOLUTION
Si ce n’est pas déjà le cas, modifiez votre programme pour qu’il y ait au plus un
if
.Si ce n’est pas déjà le cas, modifiez votre programme pour qu’il n’y ait pas de
if
.
Indication : remarquez que l’expression booléenne qui sert de condition auif
a déjà la valeur recherchée (voir aussi le cours : «Erreurs classiques avec les conditionnelles»)./// BEGIN SOLUTION
bool est_ouvert(int heure) { return (heure >= 10 and heure <= 12) or (heure >= 14 and heure <= 19); }
Remarquez la concision et la simplicité.
/// END SOLUTION
Instructions itératives: boucle while
et for
#
Exercice 3 : Programme mystère
Exécutez pas à pas le fragment de programme suivant pour \(a=3\) et \(b=11\):
while ( b >= a ) { b = b - a; }
/// BEGIN SOLUTION
Exécution pas à pas : on indique les valeurs des variables à chaque étape.
instruction
a
b
b >= a
while ( b >=a )
3
11
true
b = b -a
3
8
true
while ( b >=a )
3
8
true
b = b -a
3
5
true
while ( b >=a )
3
5
true
b = b -a
3
2
false
while ( b >=a )
3
2
false
fin du programme
/// END SOLUTION
Pour \(a\) et \(b\) entiers positifs quelconques, quelle est la valeur de \(b\) après la boucle?
/// BEGIN SOLUTION
La valeur de b après la boucle pour a et b quelconques est
b % a
, le reste de la division euclidienne de b par a./// END SOLUTION
Exercice 4 : logarithme entier en base \(2\)
Écrivez un programme dont l’entrée est un entier positif
n
et qui calcule le plus petit \(i\) de la forme \(2^k\) tel que \(n\leq i\). Rappel: il n’y a pas d’opérateur puissance enC++
.
Indication : partir dei=1
et le multiplier par \(2\) tant que nécessaire./// BEGIN SOLUTION
// Entrée : un entier n // Sortie : un entier stocké dans la variable i // de la forme 2^k tel que n <= i int i; i = 1; while (n > i){ i = i * 2; }
/// END SOLUTION
Modifiez votre programme pour que la sortie soit
k
tel que \(i=2^k\) (où \(i\) est l’entier défini à la question précédente)./// BEGIN SOLUTION
// Entrée : un entier n // Sortie : un entier stocké dans la variable k // tel que i = 2^k où n <= i int i, k; i = 1; k = 0; while (n > i){ i = i * 2; k++; }
/// END SOLUTION
Notes aux enseignants
Normalement, les étudiants ont davantage vu la boucle
while
quefor
jusqu’à cet exercice. Passez le temps nécessaire sur cet exercice car il leur est utile pour assimiler la syntaxe de la bouclefor
et la différence avec lewhile
.Si vous corrigez au tableau, arrangez-vous pour avoir les deux versions (
while
etfor
) au tableau simultanément, pour que les points communs et les différences apparaîssent bien.Insistez sur le fait que lors de l’éxécution d’une boucle for, l’incrémentation se fait à la fin du corps de la boucle, même si au niveau de l’écriture du code elle apparaît avant.
Exercice 5 : Instructions itératives avec compteur
On rappelle les exemples de programmes vus en cours pour afficher les
nombres de \(1\) à \(10\) avec respectivement une boucle while
et une
boucle for
:
int i = 1;
while ( i <= 10 ) {
cout << i << endl; // Affiche la valeur de i
i = i + 1;
}
for ( int i = 1; i <= 10; i = i + 1 ) {
cout << i << endl; // Affiche la valeur de i
}
Dans chacun de ces deux programmes, entourez la déclaration du compteur, l’initialisation, la condition et l’incrémentation.
Adaptez le premier exemple pour afficher les nombres pairs inférieurs ou égaux à \(10\), en commençant par \(0\). De même avec le deuxième exemple.
/// BEGIN SOLUTION
int i = 0; while ( i <= 10 ) { cout << i << endl; i = i + 2; }
for ( int i = 0; i <= 10; i = i + 2 ) { cout << i << endl; }
/// END SOLUTION
Même chose pour afficher les nombres de \(10\) à \(1\);
/// BEGIN SOLUTION
int i = 10; while ( i >= 0 ) { cout << i << endl; i = i - 1; }
for ( int i = 10; i >= 0; i = i-1 ) { cout << i << endl; }
/// END SOLUTION
Même chose pour afficher les nombres entiers de carré inférieur à \(10\);
/// BEGIN SOLUTION
int i = 0; while ( i*i <= 10 ) { cout << i << endl; i++; }
for ( int i = 0; i*i <= 10; i++ ) { cout << i << endl; }
/// END SOLUTION
Même chose pour calculer la valeur de la somme \(1^2 + 2^2 + \cdots + 10^2\).
/// BEGIN SOLUTION
int accumulateur = 0; int compteur = 1; while ( compteur <= n ) { accumulateur = accumulateur + compteur * compteur; compteur++; }
int accumulateur = 0; for (int compteur = 1; compteur <= n ; compteur++ ) { accumulateur = accumulateur + compteur * compteur; }
/// END SOLUTION
À votre avis, dans chacun des cas ci-dessus, laquelle des deux formes est la plus naturelle?
/// BEGIN SOLUTION
Pour les exemples de cet exercice, c’est la boucle for
qui est plus
naturelle, du fait de la présence naturelle d’un compteur simple.
C’est un peu plus ambigu pour la question 4 du fait d’une condition
plus compliquée qu’une simple borne; d’ailleurs, en Python, ce serait
compliqué de faire cette question avec une boucle for
.
/// END SOLUTION
Exercice 6 : \(\clubsuit\) Nombres premiers
Écrivez une fonction qui prend en argument (entrée) un entier \(n\) et teste si \(n\) est un nombre premier (c’est-à-dire renvoie
true
si \(n\) est premier etfalse
sinon).Écrivez une fonction qui prend en argument un entier \(n\) et affiche tous les nombres premiers entre \(1\) et \(n\).
Écrivez une fonction qui affiche les \(n\) premiers nombres premiers.
/// BEGIN SOLUTION
bool premier(int n) {
if (n == 1) {
return false ;
}
for (int i = 2; i < n; i++){
if (n % i == 0 ) {
return false;
}
}
return true ;
}
void nombres_premiers(int n) {
for (int i = 2 ; i <= n ; i++) {
if (premier(i)) {
cout << i << " " ;
}
}
}
void premiers_nombres_premiers(int n) {
int compteur = 0 ;
int i = 2 ;
while (compteur < n) {
if (premier(i)) {
cout << i << " " ;
compteur++ ;
}
i++ ;
}
}
/// END SOLUTION
Exercice 7 : \(\clubsuit\) Dates
Écrivez une fonction qui prend en entrée une date sous la forme de trois entiers jour / mois / année, et teste si c’est une date valide. Pour l’instant, on ignore les années bissextiles. Par exemple:
date_valide(28, 5, 1973)
renvoietrue
date_valide(31, 2, 2015)
renvoiefalse
/// BEGIN SOLUTION
// Entrées: trois entiers j, m et a contenant le jour, le mois et l'année // Sortie : un booléen indiquant si la date est valide. bool valide(int j, int m, int a) { if (m < 12) { if ((m == 1) or (m == 3) or (m == 5) or (m == 7) or (m == 8) or (m == 10) or (m == 12)) { return (j <= 31); } else if (m != 2) { return (j <= 30); } else { return (j <= 28); } } else { return false; } }
/// END SOLUTION
Écrivez une fonction qui prend en argument une date valide sous la forme de trois entiers et affiche la date du lendemain. Par exemple:
jour_suivant(18, 12, 2017)
afficheLe jour suivant est le 19 12 2018
.
/// BEGIN SOLUTION
// Entrées: trois entiers j, m et a contenant le jour, le mois et l'année // Sortie : Aucune mais affichage du jour suivant. void jour_suivant (int j, int m, int a) { if (j < 28 or (j < 31 and ((m == 3) or (m == 5) or (m == 7) or (m == 8) or (m == 10) or (m == 12))) or (j < 30 and ((m == 1) or (m == 4) or (m == 6) or (m == 9) or (m == 11)))) { cout << "Le jour suivant est le " << jour + 1 << " / " << m << " / " << a << endl; } else if (m < 12) { cout << "Le jour suivant est le " << 1 << " / " << m + 1 << " / " << a; } else { cout << "Le jour suivant est le 1 / 1 / " << a + 1; } }
/// END SOLUTION
Reprenez la question 1 en considérant les années bissextiles (une année est bissextile si elle est divisible par 4, mais pas 100 sauf si elle est divisible par 400).
/// BEGIN SOLUTION
// Entrées: trois entiers j, m et a contenant le jour, le mois et l'année // Sortie : un booléen indiquant si la date est valide, // y compris pour les années bissextiles. int valide_bissextile(int j, int m, int a) { if (m < 12){ if ((m == 1) or (m == 3) or (m == 5) or (m == 7) or (m == 8) or (m == 10) or (m == 12)) { return (j <= 31); } else if (m != 2){ return (j <= 30); } else if (a % 400 == 0 or (a % 4 == 0 and a % 100 != 0)){ return (j <= 29); } else { return (j <= 28); } } else { return false; } }
/// END SOLUTION
Écrivez une fonction qui prend en argument une date valide et renvoie le jour de la semaine de cette date.
Projet Euler 19: Combien de 1 du mois ont été des dimanches au XXe siècle?