Instructions et flux de contrôle
Une instruction C ++ simple est chacune des instructions individuelles d’un programme, comme les déclarations de variable et les expressions vues dans les sections précédentes. Ils se terminent toujours par un point-virgule (;) et sont exécutés dans le même ordre dans lequel ils apparaissent dans un programme.
Mais les programmes ne se limitent pas à une séquence d’instructions linéaire. Au cours de son processus, un programme peut répéter des segments de code, ou prendre des décisions et se bifurquer. À cette fin, C ++ fournit des instructions de contrôle de flux permettant de spécifier ce que doit faire notre programme, quand et dans quelles circonstances.
De nombreuses instructions de contrôle de flux expliquées dans cette section nécessitent une instruction générique dans le cadre de sa syntaxe. Cette instruction peut être une simple instruction C ++, telle qu’une seule instruction, terminée par un point-virgule (;), ou une instruction composée. Une instruction composée est un groupe d’instructions (chacune d’entre elles terminée par son propre point-virgule), mais toutes regroupées dans un bloc, entourées d’accolades: {}:
{instruction1; instruction2; instruction3;}
Le bloc entier est considéré comme une seule instruction (composé de plusieurs sous-instructions). Chaque fois qu’une instruction générique fait partie de la syntaxe d’une instruction de contrôle de flux, il peut s’agir d’une instruction simple ou composée.
Sommaire
Déclarations de sélection: if et else
Le mot-clé if est utilisé pour exécuter une instruction ou un bloc si et seulement si une condition est remplie. Sa syntaxe est la suivante:
if (condition) déclaration
Ici, condition est l’expression en cours d’évaluation. Si cette condition est vraie, l’instruction est exécutée. S’il est faux, l’instruction n’est pas exécutée (elle est simplement ignorée) et le programme continue immédiatement après l’instruction de sélection complète.
Par exemple, le fragment de code suivant imprime le message (x = 100), uniquement si la valeur stockée dans la variable x est bien 100:
if (x == 100) cout << "x = 100";
Si x n’est pas exactement 100, cette instruction est ignorée et rien n’est imprimé.
Si vous souhaitez inclure plusieurs instructions à exécuter lorsque la condition est remplie, ces instructions doivent être placées entre accolades ({}), formant un bloc:
if (x == 100) { cout << "x est"; cout << x; }
Comme d’habitude, l’indentation et les sauts de ligne dans le code n’ont aucun effet. Le code ci-dessus est donc équivalent à:
if (x == 100) {cout << "x est"; cout << x; }
Les instructions de sélection avec if peuvent également spécifier ce qui se passe lorsque la condition n’est pas remplie, en utilisant le mot clé else pour introduire une instruction alternative. Sa syntaxe est la suivante:
if (condition) instruction1 else instruction2
où instruction1 est exécuté dans le cas où la condition est vraie et dans le cas contraire, instruction2 est exécuté.
Par exemple:
if (x == 100) cout << "x est 100"; else cout << "x n'est pas 100";
Ceci imprime x est 100, si x a effectivement une valeur de 100, mais si ce n’est pas le cas, et seulement si ce n’est pas le cas, x est différent de 100.
Plusieurs structures if + else peuvent être concaténées dans le but de vérifier une plage de valeurs. Par exemple:
if (x> 0) cout << "x est positif"; else if (x <0) cout << "x est négatif"; else cout << "x est 0";
Ceci affiche si x est positif, négatif ou nul en concaténant deux structures if-else. Là encore, il aurait également été possible d’exécuter plus d’une instruction par cas en les regroupant dans des blocs entre accolades: {}.
Instruction d’itération (les boucles)
Les boucles répètent une déclaration un certain nombre de fois ou pendant qu’une condition est remplie. Ils sont introduits par les mots-clés while, do et for.
La boucle while
Le type de boucle le plus simple est la boucle while. Sa syntaxe est la suivante:
While (expression) instructions
La boucle while répète simplement l’instruction tant que expression est vraie. Si, après l’exécution d’une instruction, expression n’est plus vraie, la boucle se termine et le programme continue juste après la boucle. Par exemple, regardons un compte à rebours en utilisant une boucle while:
// compte à rebours personnalisé en utilisant while #include <iostream> using namespace std; int main () { int n = 10; while (n> 0) { cout << n << ","; --n; } cout << "décollage! \ n"; }
La première instruction de main donne n la valeur 10. Il s’agit du premier nombre du compte à rebours. La boucle while commence alors: si cette valeur remplit la condition n> 0 (que n est supérieur à zéro), le bloc qui suit la condition est exécuté et répété tant que la condition (n> 0) reste en cours vrai.
L’ensemble du processus du programme précédent peut être interprété selon le script suivant (commençant par main):
- n se voit attribuer une valeur
- La condition while est vérifiée (n> 0). À ce stade, il y a deux possibilités:
la condition est vraie: l’instruction est exécutée
la condition est fausse: ignore l’instruction et continue après
Executer l’instruction:
cout << n << « , »;
–n;
(affiche la valeur de n et diminue n de 1) - Fin du bloc. Revenez automatiquement à l’étape 2.
- Continuez le programme juste après le bloc:
imprimer décollage! et terminer le programme.
Une chose à considérer avec les boucles While est que la boucle doit se terminer à un moment donné. Par conséquent, la déclaration doit modifier les valeurs vérifiées dans la condition d’une manière ou d’une autre, de manière à forcer celle-ci à devenir fausse à un moment donné. Sinon, la boucle continuera à boucler pour toujours. Dans ce cas, la boucle inclut –n, qui diminue de un la valeur de la variable évaluée dans la condition (n) – elle finira par rendre la condition (n> 0) fausse après un certain nombre d’itérations de boucle. Pour être plus précis, après 10 itérations, n devient 0, ce qui rend la condition non plus vraie et met fin à la boucle while.
Notez que la complexité de cette boucle est triviale pour un ordinateur et que tout le compte à rebours est effectué instantanément, sans délai pratique entre les éléments du compte (si cela vous intéresse, voir sleep_for pour un exemple de compte à rebours avec retards).
La boucle do-while
Une boucle très similaire est la boucle do-while, dont la syntaxe est la suivante:
do instructions while (condition);
Il se comporte comme une boucle while, sauf que la condition est évaluée après l’exécution de l’instruction au lieu d’avant, garantissant au moins une exécution de l’instruction, même si la condition n’est jamais remplie. Par exemple, l’exemple de programme suivant reprend n’importe quel texte introduit par l’utilisateur jusqu’à ce que l’utilisateur entre au revoir:
// echo machine #include <iostream> #include <string> using namespace std; int main () { string str; do { cout << "Saisir le texte:"; getline (cin, str); cout << "Vous avez entré:" << str << '\ n'; } while (str! = "au revoir"); }
Résultat de l’exécution :
Saisir le texte: bonjour Vous avez entré: bonjour Saisir le texte: qui est là? Vous avez entré: qui est là? Saisir le texte: au revoir Vous avez entré: au revoir
La boucle do-while est généralement préférée à une boucle while lorsque l’instruction doit être exécutée au moins une fois, par exemple lorsque la condition vérifiée jusqu’à la fin de la boucle est déterminée dans l’instruction de boucle elle-même. Dans l’exemple précédent, l’entrée de l’utilisateur dans le bloc détermine ce qui permet de déterminer si la boucle se termine. Et ainsi, même si l’utilisateur veut terminer la boucle le plus tôt possible en entrant au revoir, le bloc de la boucle doit être exécuté au moins une fois pour demander une entrée et la condition ne peut, en fait, être déterminée qu’après. est exécuté.
La boucle for
La boucle for est conçue pour itérer un certain nombre de fois. Sa syntaxe est la suivante:
for (initialisation; condition; augmentation) instruction;
Comme la boucle while, cette boucle répète l’instruction tant que la condition est vraie. Mais, en outre, la boucle for fournit des emplacements spécifiques contenant une expression d’initialisation et d’augmentation, exécutées respectivement avant le début de la boucle et après chaque itération. Par conséquent, il est particulièrement utile d’utiliser des variables de compteur comme condition.
Cela fonctionne de la manière suivante:
- l’initialisation est exécutée. Généralement, cela déclare une variable de compteur et lui attribue une valeur initiale. Ceci est exécuté une seule fois, au début de la boucle.
- la condition est vérifiée. Si c’est vrai, la boucle continue; sinon, la boucle se termine et l’instruction est ignorée.
- l’instruction est exécutée. Comme d’habitude, il peut s’agir d’une simple instruction ou d’un bloc entouré d’accolades {}.
- L’augmentation est exécutée et la boucle revient à l’étape 2.
- la boucle se termine: l’exécution se poursuit par l’instruction suivante.
Voici l’exemple de compte à rebours utilisant une boucle for:
// compte à rebours à l'aide d'une boucle for #include <iostream> using namespace std; int main () { for (int n = 10; n> 0; n--) { cout << n << ","; } cout << "décollage! \ n"; }
Les trois champs d’une boucle for sont optionnels. Ils peuvent être laissés vides, mais dans tous les cas, les points-virgules entre eux sont obligatoires. Par exemple, for (; n <10;) est une boucle sans initialisation ni augmentation (équivalent à une boucle while); et pour (; n <10; ++ n) est une boucle avec augmentation, mais aucune initialisation (peut-être parce que la variable a déjà été initialisée avant la boucle). Une boucle sans condition équivaut à une boucle dont la condition est vraie (c’est-à-dire une boucle infinie).
Étant donné que chacun des champs est exécuté à un moment particulier du cycle de vie d’une boucle, il peut être utile d’exécuter plus d’une expression unique que par une initialisation, une condition ou une instruction. Malheureusement, ce ne sont pas des déclarations, mais plutôt des expressions simples et ne peuvent donc pas être remplacées par un bloc. En tant qu’expressions, ils peuvent toutefois utiliser l’opérateur de virgule (,): cet opérateur est un séparateur d’expression et peut séparer plusieurs expressions lorsqu’un seul est généralement attendu. Par exemple, en l’utilisant, il serait possible à une boucle for de gérer deux variables de compteur, en les initialisant et en les augmentant:
for (n = 0, i = 100; n! = i; ++ n, - i) { // quoi que ce soit ici ... }
Cette boucle s’exécutera 50 fois si ni n ni i ne sont modifiés dans la boucle:
n commence avec une valeur de 0 et i avec 100, la condition est n! = i (c.-à-d. que n n’est pas égal à i). Puisque n est augmenté de un et que i est diminué de un à chaque itération, la condition de la boucle deviendra fausse après la 50e itération, lorsque n et i sont égaux à 50.
Plage basée sur la boucle
La boucle for a une autre syntaxe, qui est utilisée exclusivement avec des plages:
for (déclaration: plage) instruction;
Ce type de boucle for parcourt tous les éléments de la plage, où déclaration déclare une variable capable de prendre la valeur d’un élément de cette plage. Les plages sont des séquences d’éléments, y compris des tableaux, des conteneurs et tout autre type prenant en charge les fonctions begin et end; La plupart de ces types n’ont pas encore été introduits dans ce tutoriel, mais nous connaissons déjà au moins un type de plage: les chaînes, qui sont des séquences de caractères.
Un exemple de boucle for basée sur une plage utilisant des chaînes:
// basé sur la boucle for #include <iostream> #include <string> using namespace std; int main () { string str {"Hello!"}; for (char c: str) { cout << "[" << c << "]"; } cout << '\ n'; }
Notez que ce qui précède les deux points (:) dans la boucle for correspond à la déclaration d’une variable char (les éléments d’une chaîne sont de type char). Nous utilisons ensuite cette variable, c, dans le bloc d’instructions pour représenter la valeur de chacun des éléments de la plage.
Cette boucle est automatique et ne nécessite la déclaration explicite d’aucune variable de compteur.
Les boucles basées sur la plage utilisent généralement aussi la déduction de type pour le type des éléments avec auto. Typiquement, la boucle basée sur la plage ci-dessus peut également être écrite comme suit:
for (auto c: str) cout << "[" << c << "]";
Ici, le type de c est automatiquement déduit comme le type des éléments dans str.
Instructions de saut
Les instructions de saut permettent de modifier le flux d’un programme en effectuant des sauts vers des emplacements spécifiques.
L’instruction Break
break laisse une boucle, même si la condition pour sa fin n’est pas remplie. Il peut être utilisé pour terminer une boucle infinie ou pour la forcer à se terminer avant sa fin naturelle. Par exemple, arrêtons le compte à rebours avant sa fin naturelle:
// exemple de boucle avec break #include <iostream> using namespace std; int main () { for (int n = 10; n> 0; n--) { cout << n << ","; si (n == 3) { cout << "compte à rebours avorté!"; Pause; } } }
L’instruction continue
L’instruction continue force le programme à ignorer le reste de la boucle dans l’itération actuelle, comme si la fin du bloc d’instructions avait été atteinte, le faisant ainsi sauter au début de l’itération suivante. Par exemple, passons au numéro 5 de notre compte à rebours:
// exemple de boucle avec continue #include <iostream> using namespace std; int main () { for (int n = 10; n> 0; n--) { si (n == 5) continue; cout << n << ","; } cout << "décollage! \ n"; }
L’instruction goto
goto permet de faire un saut absolu à un autre point du programme. Ce saut inconditionnel ignore les niveaux d’imbrication et ne provoque pas de déroulement automatique de la pile. C’est donc une caractéristique à utiliser avec précaution, et de préférence dans le même bloc d’instructions, en particulier en présence de variables locales.
Le point de destination est identifié par une étiquette, qui est ensuite utilisée comme argument pour l’instruction goto. Une étiquette est composée d’un identifiant valide suivi de deux points (:).
goto est généralement considéré comme une fonctionnalité de bas niveau, sans cas d’utilisation particulier dans les paradigmes de programmation de haut niveau modernes généralement utilisés avec C ++. Mais, à titre d’exemple, voici une version de notre boucle de compte à rebours utilisant goto:
// exemple de boucle goto #include <iostream> using namespace std; int main () { int n = 10; mylabel: cout << n << ","; n--; if (n> 0) passez à mylabel; cout << "décollage! \ n"; }
Une autre instruction de sélection: switch
La syntaxe de l’instruction switch est un peu particulière. Son but est de rechercher une valeur parmi un certain nombre d’expressions constantes possibles. C’est quelque chose de similaire à la concaténation d’instructions if-else, mais limitée aux expressions constantes. Sa syntaxe la plus typique est:
switch (expression) { case constant1: group-of-statements-1; break; case constant2: group-of-statements-2; break; . . . default: default-group-of-statements }
Cela fonctionne de la manière suivante: switch évalue une expression et vérifie si elle est équivalente à constant1; si c’est le cas, il exécute le groupe de déclarations-1 jusqu’à ce qu’il trouve l’instruction break. Lorsqu’il trouve cette instruction break, le programme saute à la fin de l’instruction switch entière (l’accolade fermante).
Si expression n’était pas égale à constant1, il est ensuite comparé à constant2. S’il est égal à cela, il exécute le groupe d’instructions-2 jusqu’à ce qu’une pause soit trouvée, puis saute à la fin du commutateur.
Enfin, si la valeur de expression ne correspond à aucune des constantes spécifiées précédemment (il peut y en avoir un nombre quelconque), le programme exécute les instructions incluses après le libellé par défaut: label, s’il existe (car il est facultatif).
Les deux fragments de code suivants ont le même comportement, démontrant l’équivalent if-else d’une instruction switch:
exemple de switch | équivalence if-else |
switch (x) { case 1: cout << "x is 1"; break; case 2: cout << "x is 2"; break; default: cout << "valeur de l'inconnu x"; } |
if (x == 1) { cout << "x is 1"; } else if (x == 2) { cout << "x is 2"; } else { cout << "valeur de l'inconnu x"; } |
L’instruction switch a une syntaxe quelque peu particulière héritée des débuts des premiers compilateurs C, car elle utilise des étiquettes au lieu de blocs. Dans l’utilisation la plus typique (indiquée ci-dessus), cela signifie que des instructions de séparation sont nécessaires après chaque groupe d’instructions pour une étiquette particulière. Si break n’est pas inclus, toutes les instructions suivant le cas (y compris celles sous toute autre étiquette) sont également exécutées jusqu’à ce que la fin du bloc commutateur ou une instruction de saut (telle que break) soit atteinte.
Si l’exemple ci-dessus ne comportait pas l’instruction break après le premier groupe pour le cas un, le programme ne sauterait pas automatiquement à la fin du bloc de commutateur après avoir imprimé x est égal à 1, et continuerait plutôt à exécuter les instructions dans le cas deux (imprimant ainsi x est 2). Il continuerait ensuite à le faire jusqu’à ce qu’une instruction break soit rencontrée ou jusqu’à la fin du bloc de commutation. Cela évite de placer les instructions de chaque cas entre accolades {} et peut également s’avérer utile pour exécuter le même groupe d’instructions pour différentes valeurs possibles. Par exemple:
switch (x) { cas 1: cas 2: cas 3: cout << "x est 1, 2 ou 3"; break; default: cout << "x n'est pas 1, 2 ni 3"; }
Notez que switch est limité pour comparer l’expression évaluée à des étiquettes qui sont des expressions constantes. Il n’est pas possible d’utiliser des variables en tant qu’étiquettes ou en tant que plages, car elles ne sont pas des expressions constantes C ++ valides.
Pour vérifier les plages ou les valeurs qui ne sont pas constantes, il est préférable d’utiliser des concaténations d’instructions if et else if.