Les boucles en C++ (C++17 et C++20)
Une boucle est un mécanisme qui vous permet d'exécuter une instruction ou un bloc d'instructions de manière répétée jusqu'à ce qu'une condition particulière soit remplie. Deux éléments essentiels composent une boucle : l'instruction ou le bloc d'instructions qui doit être exécuté de manière répétée forme ce que l'on appelle le corps de la boucle, et une condition de boucle quelconque qui détermine quand arrêter de répéter la boucle. Une seule exécution du corps d'une boucle est appelée une itération.
Une condition de boucle peut prendre différentes formes pour fournir différentes manières de contrôler la boucle. Par exemple, une condition de boucle peut faire ce qui suit :
- Exécuter une boucle un nombre donné de fois
- Exécuter une boucle jusqu'à ce qu'une valeur donnée dépasse une autre valeur
- Exécuter une boucle jusqu'à ce qu'un caractère particulier soit saisi au clavier
- Exécuter une boucle pour chaque élément d'une collection d'éléments
Vous pouvez choisir la condition de la boucle en fonction des circonstances. Vous disposez des variétés de boucles suivantes :
- La boucle for permet principalement d'exécuter la boucle un nombre prescrit de fois, mais elle offre une flexibilité considérable au-delà de ce nombre.
- La boucle for basée sur les collections (foreach) exécute une itération pour chaque élément d'une collection d'éléments.
- La boucle while poursuit son exécution tant qu'une condition spécifiée est vraie. La condition est vérifiée au début d'une itération, donc si la condition est fausse au départ, aucune itération de la boucle n'est exécutée.
- La boucle do-while poursuit son exécution tant qu'une condition donnée est vraie. Elle diffère de la boucle while en ce que la boucle do-while vérifie la condition à la fin d'une itération. Cela implique qu'au moins une itération de boucle est toujours exécutée.
Boucle for
La boucle for exécute généralement une instruction ou un bloc d'instructions un nombre prédéterminé de fois, mais vous pouvez également l'utiliser d'autres manières. Vous spécifiez le fonctionnement d'une boucle for à l'aide de trois expressions séparées par des points-virgules entre parenthèses après le mot-clé for.
Syntaxe
for (initialisation; condition; iteration) { // corps de la boucle } // instructions suivantes
Vous pouvez omettre tout ou partie des expressions contrôlant une boucle for, mais vous devez toujours inclure les points-virgules.
L'expression d'initialisation est évaluée une seule fois, au début de la boucle. La condition de la boucle est ensuite vérifiée et, si elle est vraie, l'instruction ou le corps de la boucle est exécuté. Si la condition est fausse, la boucle se termine et l'exécution se poursuit avec l'instruction qui suit la boucle. Après chaque exécution de l'instruction ou du bloc de boucle, l'expression d'itération est évaluée, et la condition est vérifiée pour décider si la boucle doit continuer.
Dans l'utilisation la plus typique de la boucle for, la première expression initialise un compteur, la deuxième expression vérifie si le compteur a atteint une limite donnée, et la troisième expression incrémente le compteur.
Exemple 1
for (int i = 0; i < 10; i++) { cout << i; }
La première expression définit i comme un nombre entier avec une valeur initiale de 0. La deuxième expression, la condition de la boucle, est vraie tant que i est inférieur à 10, donc la boucle continue tant que i est inférieur à 10. Lorsque i atteint 10, l'expression sera fausse, et la boucle se termine donc. La troisième expression incrémente i à la fin de chaque itération de la boucle.
Comme toujours, le compilateur ignore tous les espaces blancs dans l'instruction for. De plus, si le corps de la boucle est constitué d'une seule instruction, les accolades sont facultatives. Ainsi, si vous le souhaitez, vous pouvez formater la boucle for de la manière suivante :
Exemple 2
for (int i = 0; i < 10; i++) cout << i;
Non seulement il est légal de définir des variables telles que i dans une expression d'initialisation de boucle for, mais c'est courant. Cela a des implications importantes. Une boucle définit une portée. L'instruction ou le bloc de la boucle, y compris toutes les expressions qui contrôlent la boucle, font partie de la portée d'une boucle. Toute variable automatique déclarée dans la portée d'une boucle n'existe pas en dehors de celle-ci. Comme i est défini dans la première expression, il est local à la boucle, de sorte que lorsque la boucle se termine, i n'existe plus. Lorsque vous devez être en mesure d'accéder à la variable de contrôle de la boucle après la fin de celle-ci, il suffit de la définir avant la boucle, comme ceci :
Exemple 3
int i; for (i = 0; i < 10; i++) cout << i;
Vous pouvez maintenant accéder à i après la boucle - sa valeur sera alors 10 dans ce cas.
La boucle for a plusieurs variantes. Par exemple, les premier et troisième paramètres peuvent être divisés en plusieurs instructions en utilisant l'opérateur virgule.
Exemple 4
for (int k = 0, m = 0; k < 5; ++k, m--) { cout << k+m; }
Bien que la virgule semble n'être qu'un humble séparateur, il s'agit en fait d'un opérateur binaire. Il combine deux expressions en une seule, où la valeur de l'opération est la valeur de son opérande droit. Cela signifie que partout où vous pouvez mettre une expression, vous pouvez également mettre une série d'expressions séparées par des virgules.
Il est également possible d'omettre l'un des paramètres. En voici quelques exemples.
Exemple 5
for (;;) { // Boucle infinie } for (int i=0; i < 10; ) { // incrémenter i à l'intérieur de la boucle } int cpt = 0; for (; cpt < 10; ++cpt) { // ... } // Utiliser cpt après la boucle
Contrôler une boucle for avec des valeurs à virgule flottante
Jusqu'à présent, les exemples de boucle for ont utilisé une variable entière pour contrôler la boucle, mais vous pouvez utiliser ce que vous voulez. Le code suivant utilise des valeurs à virgule flottante pour contrôler la boucle :
Exemple 6
#include <iostream> using namespace std; int main(void){ for (double r {2.5}; r <= 20.0; r += 2.5) { cout << r << '\t'; } return 0; }
2.5 5 7.5 10 12.5 15 17.5 20
Cette boucle est contrôlée par la variable r, qui est de type double. Elle a une valeur initiale de 2,5 et est incrémentée à la fin de chaque itération de la boucle jusqu'à ce qu'elle dépasse 20,0, après quoi la boucle se termine.
La boucle for basée sur les collections (Similaire à foreach dans d'autres langages de programmation)
La boucle for basée sur une collection itère sur toutes les valeurs de la collection donnée. Cela soulève une question immédiate : qu'est-ce qu'une collection ? Une collection est un ensemble d'éléments, une chaîne de caractères est une collection de caractères. Les conteneurs fournis par la bibliothèque standard sont également tous des collections.
C++11 a introduit une syntaxe de boucle for basée sur les collections pour l'itération dans les tableaux et autres types de conteneurs. À chaque itération, l'élément suivant du tableau est lié à la variable spécifiée, dans ce cas une variable coll_declaration, et la boucle continue jusqu'à ce qu'elle ait parcouru tout le tableau.
Syntaxe
for (coll_declaration : coll_expression) corps de la boucle;
Exemple 7
#include <iostream> using namespace std; int main(void){ int T[4] = {1, 7, 13, 17}; for (int elem : T) { cout << elem << '\t'; } return 0; }
1 7 13 17
Bien sûr, le compilateur connaît le type des éléments du tableau de valeurs, donc vous pourriez aussi laisser le compilateur déterminer le type de elem en écrivant la première boucle comme ceci :
Exemple 8
#include <iostream> using namespace std; int main(void){ int T[4] = {1, 7, 13, 17}; for (auto elem : T) { cout << elem << '\t'; // "123" } return 0; }
En utilisant le mot-clé auto, le compilateur déduit le type correct pour elem. Le mot-clé auto est souvent utilisé avec la boucle for basée sur la collection. C'est une façon agréable d'itérer sur tous les éléments d'un tableau ou d'autres types de conteneurs. Vous n'avez pas besoin de connaître le nombre d'éléments. Le mécanisme de la boucle s'en charge.
Notez que les valeurs de la collection sont affectées à la variable elem. Cela signifie que vous ne pouvez pas modifier les éléments des valeurs en modifiant la valeur de elem. Pour modifier les valeurs de la collection, nous utilisons une variable de référence comme suit :
Exemple 9
#include <iostream> using namespace std; int main(void){ int T[4] = {1, 7, 13, 17}; for (auto &elem : T) { elem=5; } for (auto elem : T) { cout << elem << '\t'; // "123" } return 0; }
C++20 a étendu la boucle for basée sur la collection en lui permettant d'inclure un initialiseur. Ceci est utile pour garder les portées serrées lors de l'itération sur un conteneur temporaire qui n'est nécessaire que pour la durée de la boucle.
Syntaxe
for ([initialisation;] coll_declaration : coll_expression) corps de la boucle;
Les crochets sont pour référence seulement, et ils indiquent que la partie d'initialisation est facultative. La possibilité d'ajouter une instruction d'initialisation aux boucles for basées sur la collection a été ajoutée en C++ 20 et est, à part le fait qu'elle est facultative, complètement analogue à celle des boucles for régulières. Vous pouvez l'utiliser pour initialiser une ou plusieurs variables que vous pouvez ensuite utiliser dans le reste de la boucle for.
La coll_expression identifie la collection qui est la source des données, et la coll_declaration identifie une variable à laquelle chacune des valeurs de cette collection sera affectée tour à tour, une nouvelle valeur étant affectée à chaque itération.
Exemple 10
#include <iostream> using namespace std; int main(void){ for (int T[4] = {1, 7, 13, 17};int elem : T) { cout << elem << '\t'; } return 0; }
La boucle while
La boucle while parcourt le bloc de code uniquement si sa condition est vraie et continuera à boucler tant que la condition restera vraie. Gardez à l'esprit que la condition n'est vérifiée qu'au début de chaque itération (boucle).
Syntaxe
while ( condition ) { // corps de la boucle } // instructions après la boucle
Vous pouvez utiliser n'importe quelle expression pour contrôler la boucle, à condition qu'elle donne une valeur de type bool ou qu'elle puisse être implicitement convertie en type bool. Si l'expression de la condition de boucle donne une valeur numérique, par exemple, la boucle continue tant que la valeur est différente de zéro. Une valeur nulle termine la boucle.
Exemple 11
int i = 0; while (i < 10) { cout << i << '\t'; i++; }
Toute boucle for peut être écrite comme une boucle while équivalente, et vice versa. Par exemple, une boucle for a la forme générique suivante :
for (initialisation; condition; iteration) body
Cela peut généralement être écrit à l'aide d'une boucle while comme suit :
{ initialisation; while (condition) { body iteration; } }
La boucle while doit être entourée d'une paire supplémentaire d'accolades pour émuler la façon dont les variables déclarées dans la portée de la boucle for d'origine.
La boucle do-while
La boucle do-while est similaire à la boucle while en ce sens que la boucle continue tant que la condition de boucle spécifiée reste vraie. La seule différence est que la condition de boucle est vérifiée à la fin de la boucle do-while, plutôt qu'au début, de sorte que l'instruction de boucle est toujours exécutée au moins une fois. Ce type de logique est idéal pour les situations où vous avez un bloc de code que vous souhaitez toujours exécuter une fois et que vous souhaitez peut-être exécuter plusieurs fois.
Syntaxe
do { // corps de la boucle... } while (condition);
Notez que le point-virgule qui vient après la condition entre parenthèses est absolument nécessaire. Si vous l'omettez, le programme ne se compilera pas.
Exemple 12
Supposons que vous souhaitiez calculer la moyenne d'un nombre arbitraire de valeurs d'entrée (les notes des élèves, par exemple) sans les stocker. Vous n'avez aucun moyen de savoir à l'avance combien de valeurs seront entrées, mais il est prudent de supposer que vous en aurez toujours au moins une, car si vous ne le faisiez pas, il n'y aurait aucun intérêt à exécuter le programme. Cela en fait un candidat idéal pour une boucle do-while.
#include <iostream> using namespace std; int main(void){ char rep {}; int nb {}; double note {}; double somme {}; do { cout << "Saisir une note : "; cin >> note; somme+=note; ++nb; cout << "Voulez-vous en saisir une autre ? (o/n) : "; cin >> rep; } while (rep=='o'); cout << "La moyenne est : " << somme/nb << '\n'; return 0; }
Saisir une note : 12 Voulez-vous en saisir une autre ? (o/n) : o Saisir une note : 14 Voulez-vous en saisir une autre ? (o/n) : o Saisir une note : 10 Voulez-vous en saisir une autre ? (o/n) : o Saisir une note : 17 Voulez-vous en saisir une autre ? (o/n) : n La moyenne est : 13.25
Ce programme traite n'importe quel nombre de valeurs d'entrée sans connaissance préalable du nombre qui sera entré. Après avoir défini quatre variables requises pour l'entrée et le calcul, les valeurs des données sont lues dans une boucle do-while. Une valeur d'entrée est lue à chaque itération de boucle, et au moins une valeur sera toujours lue. La réponse à l'invite stockée dans rep détermine si la boucle se termine. Si la réponse est o, la boucle continue ; sinon, la boucle se termine.
break et continue
continue
Des situations surviennent où vous souhaitez ignorer une itération de boucle et continuer avec la suivante. L'instruction continue fait ceci :
Syntaxe
continue; // Passer à l'itération suivante
Lorsque cette instruction s'exécute dans une boucle, l'exécution est immédiatement transférée à la fin de l'itération en cours. Tant que l'expression de contrôle de boucle le permet, l'exécution continue avec l'itération suivante.
Exemple 13
#include <iostream> using namespace std; int main(void){ for(int i=0 ; i < 5 ; i++){ if(i==3){ continue; } cout << "Itération : " << i << '\n'; } return 0; }
Itération : 0 Itération : 1 Itération : 2 Itération : 4
Comme vous pouvez le voir lorsque i = 3, l'instruction continue est exécutée et les instructions qui suivent if sont ignorées et la boucle est passée directement à i = 4.
break
Parfois, il est nécessaire de mettre fin à une boucle de façon permanente ; quelque chose peut survenir dans l'instruction de la boucle qui indique qu'il est inutile de continuer. Dans ce cas, vous pouvez utiliser l'instruction break. Son effet dans une boucle est à peu près le même que dans une instruction switch ; l'exécution d'une instruction break dans une boucle met fin à la boucle immédiatement, et l'exécution se poursuit avec l'instruction qui suit la boucle.
Syntaxe
break; // termine la boucle immédiatement
Exemple 14
#include <iostream> using namespace std; int main(void){ for(int i=0; i < 5;i++){ if(i==3){ break; } cout << "Itération : " << i << '\n'; } return 0; }
Itération : 0 Itération : 1 Itération : 2