< Langage C++
fin de la boite de navigation du chapitre

Boucles & Structures Conditionnelles

En C++ on a très fréquemment besoin de contrôler les chemins d'exécutions, ce afin de réagir à certaines conditions ou pour répéter plusieurs fois un même morceau de code.

Structures conditionnelles

Les structures conditionnelles servent à effectuer des vérifications avant d'exécuter du code spécifique à la condition.

IF, ELSE

Il faut se représenter l'instruction "if" comme un test logique binaire : "si cela est vrai, alors je fais ceci, sinon, je fais cela."

Définition

Syntaxe :

if (<Conditions>)
{
    <ActionsSiConditionsVrai>
}
else
{
    <ActionsSiConditionsFausses>
}

Où <Conditions> sont les conditions à remplir pour que le bloc de <ActionsSiConditionsVrai> de la clause "if"(Si) soit exécuté, et fausses pour que <ActionsSiConditionsFausses> de la clause "else" (Sinon) soit exécuté. Il est à noter que la clause "else" est facultative.

Remarque

Dans un souci d'optimisation de code et de compréhension les conditions doivent décrire le cas unique. La clause "else" traitant tous les autres cas.

Exemple
bool vBascule = false;

if(true == vBascule)
{
    vBascule = false;
}
else 
{
    vBascule = true;
}
Fin de l'exemple

Le fait d'écrire true == vBascule n’est pas une erreur de conception :

  • Cela améliore la lisibilité du test.
  • Cela permet d'assurer le plantage à la compilation du test si on fait l'erreur de ne mettre qu'un seul égal =.
  • Cela permet de signaler aux développeur qui reliront le code que l’on veut bien la valeur true (dans le cas contraire on aurait mis false)
Panneau d’avertissement Attention: Il est dangereux et très fortement déconseillé d'enlever les accolades des clauses "if" et "else". Tout comme d’utiliser l'implémentation "else if" pour imbriquer des tests conditionnels.
Panneau d’avertissement Attention:Exemples à ne pas faire :
Début de l'exemple
Exemple
int a;
int b;

//...

if (a > b)
    FaitASuperieurB();
else if (a == b)
    FaitAEgalB();
else if ((a < b) && (a != 5))
    FaitAInferieurB();
else if (a == 5)
    FaisAInferieurBEtAEgalCinq();
    FaitAutreChose();
Fin de l'exemple

Ceci est à prohiber pour 3 raisons :

  1. D'abord, c’est débile "a = b" et "a = 5" auraient été mieux placés dans les premiers "if"
  2. Ensuite, c’est illisible et seul un initié sait comment va être exécuté "FaitAutreChose"
  3. Enfin, c’est dangereux car on ne voit pas l'organisation des chemins d'exécutions.
Panneau d’avertissement Attention: Quant au groupement "else if" cela revient à faire :
Début de l'exemple
Exemple
if(x)
a();
else if (y)
b();
else
c();
Fin de l'exemple

soit :

Début de l'exemple
Exemple
if(x)
{
    a();
}
else 
    if (y)
    {
        b()
    }
    else
    {    
        c()
    }
Fin de l'exemple

et donc :

Début de l'exemple
Exemple
if(x)
{
    a();
}
else 
{
    if (y)
    {
        b();
    }
    else
    {    
        c();
    }
}
Fin de l'exemple

Ce qui est plus lisible.


Le code de l'exemple à ne pas faire avec les accolades donnerait :

Exemple
if (a > b)
{
    FaitASuperieurB();
}
else 
{
    if (a == b)
    {
        FaitAEgalB();
    }
    else
    {
        if ((a < b) && (a != 5))
        {
            FaitAInferieurB();
        }
        else
        {
            if (a == 5)
            {
                FaisAInferieurBEtAEgalCinq();
            }
        }
    }
}
    FaitAutreChose();
Fin de l'exemple

Ce qui permet tout de suite de voir que "FaitAutreChose" ne fait pas partie des tests. En effet sans accolades les clauses "if" et "else" n'exécutent que l'instruction située juste derrière elles. De plus on voit les chemins de codes et les optimisations possibles.

Voici donc le même code optimisé

Exemple
if (a == b)
{
    FaitAEgalB();
}
else 
{
    if (a < b)
    {
        if (a == 5)
        {
            FaisAInferieurBEtAEgalCinq();
        }            
        else
        {
            FaitAInferieurB();
        }
    }
    else
    {
        FaitASuperieurB();
    }
}
FaitAutreChose();
Fin de l'exemple

On peut voir ici que le nouveau code fait non seulement la même chose que le code original mais en plus on effectue un test de moins grâce à l'optimisation.

Malheureusement il existe encore beaucoup de code industriel écrit de manière compacte (sans accolades) et possédant des "else if" imbriqués.

SWITCH, CASE, DEFAULT

Il faut se représenter l'instruction "switch" comme un test logique multi-états : "Selon la variable, si elle est à telle valeur alors faire ceci, si elle est à telle autre valeur faire cela, si elle est à encore une autre valeur faire autre chose, ..., sinon : faire le traitement par défaut.".

Panneau d’avertissement Attention: Cette structure de test conditionnel ne permet de tester que des valeurs entières ou des chars, pas des chaines ni des flottants !


Définition

Syntaxe :

switch(<Variable>)
{
    case <Valeur1>:
        <ActionsSiValeur1>;
        break;
    case <Valeur2>:
        {
            <ActionsSiValeur2>;
        }
        break;
    case <Valeur3>:
    case <Valeur4>:
        {
            <ActionsSiValeur3Ou4>;
        }
        break;
    case <Valeur5>:
        {
            <ActionsSiValeur5>;
        }
        break;
    ///...
    case <ValeurN>:
        {
            <ActionsSiValeurN>;
        }
        break;
    default:
        {
            <TraitementParDéfaut>
        }
        break;
}

Où <Variable> est la variable à tester <Valeur1> à <ValeurN> sont les différentes valeurs que <Variable> peut prendre et qui nécessitent un traitement particulier, <ActionsSiValeur1> à <ActionsSiValeurN> sont les différents traitements pour chaque valeur nécessitant leur propre traitement, <ActionsSiValeur3Ou4> est un cas où plusieurs valeurs (ici <Valeur3> et <Valeur4>) nécessitent le même traitement (remarquez l'absence de break; entre les deux cas, autrement obligatoire), <TraitementParDéfaut> signalé par la clause default est le traitement réservé à toute autre valeur que celles renseignées par les clauses case. Il est à noter que la clause default n’est pas obligatoire. Par contre il est impératif de mettre une clause break après chaque clause case suivie de code.

Dans un souci d'optimisation de code et de compréhension les valeurs renseignées dans les clauses case doivent décrire les cas uniques nécessitant des traitements personnalisés. La clause default traitant tous les autres cas.

Exemple
#include <iostream>

using namespace std;

int main (int argc, char* argv[])
{
    int vInteger = argc;

    switch (vInteger)
    {
        case 0: 
            {
                cout << "vInteger = 0" << endl;
            }
            break;
        case 1:
        case 2:
            {
                cout << "vInteger = 1 ou 2" << endl;
            } 
            break;
        default:
            {
                cout << "vInteger != (0, 1 et 2)" << endl;
            }
            break;
    }
    return 0;
}
Fin de l'exemple


Panneau d’avertissement Attention: Il est fortement conseillé de mettre entre accolades les traitements des clauses case, en particulier si les traitements en question sont longs ou utilisent des boucles ou des structures conditionnelles.

Boucles

En C++ on peut demander à un programme de répéter plusieurs fois l'exécution du même code. Cela s’appelle itérer le code, ou plus simplement faire une boucle.

Boucles FOR

La boucle "for" est une itération bornée elle est généralement associée à une variable de contrôle et à une condition afin de ne pas exécuter le code indéfiniment. En pratique, on ne l'utilise que si l’on sait ou s'il y a moyen de savoir combien de fois on doit itérer.

Définition

Syntaxe :

for(<Initialisation>;<Condition>;<ItérationContrôle>)
{
    <ItérationCode>;
}

Où <Initialisation> est la séquence d'initialisation de la boucle qui est en général utilisée pour initialiser le compteur de contrôle, <Condition> est la condition à réaliser pour que la boucle for continue d'itérer le code <ItérationCode>, et <ItérationContrôle> est la séquence d'itération du contrôle de la boucle.


Concrètement :

Exemple
#include <iostream> // nécessaire pour utiliser "std:cout"

int vLimite = 5; // limite de l'itération.
for(int vIndex = 0; vIndex < vLimite; vIndex++)
{
    std:cout << (vIndex + 1) << " / " << vLimite << "\n"; // Code itéré
}
Fin de l'exemple


La boucle "for" est à traduire littéralement par : "pour". Par analogie avec d'autres langages comme le Pascal on peut la comprendre ainsi : "Pour, De, À, Faire, Puis", soit en ce qui concerne notre exemple :

"Pour" l'entier 'vIndex', "De" la valeur '0', "À" la valeur 'vLimite', "Faire" : 'std:cout << (vIndex + 1) << " / " << vLimite;' "Puis" 'vIndex++'.

Panneau d’avertissement Attention: Il est à noter que si la condition est fausse à l'entrée de la boucle (ex: 1 < 0) alors la boucle n'effectue aucune itération. De même si la condition est toujours vraie (ex: 0 > 1) alors on ne sort jamais de la boucle. Ces deux comportements sont la plupart du temps les conséquences d'erreurs de conception.

Boucles WHILE

La boucle "while" est une forme d'itération non bornée qui permet de répéter un code tant qu'une condition est vraie. La plupart du temps cette boucle est utilisée si l’on ne connait pas l'état initial de la variable qui est utilisée dans la condition, ou que l’on ne connait pas et que l’on ne peut pas calculer le nombre d'itérations nécessaire pour que la variable atteigne son état final.

Définition

Syntaxe :

while(<Condition>)
{
    <ItérationCode>;
}

Où <Condition> est la condition pour que la boucle fasse une nouvelle itération et <ItérationCode> le code à itérer.

Exemple
#include <iostream> // nécessaire pour utiliser "std::cout"

bool vContinuer = true; // limite de l'itération.
unsigned int vFactorielle = 50;
int vResultat = 0;
while(true == vContinuer)
{
    if(0 == vFactorielle)
    {
        vResultat = vResultat + 1; 
        vContinuer = false;
    }
    else
    {
        vResultat += vFactorielle; // Ajoute factorielle au résultat.
        vFactorielle--; // décrémente factorielle.
    }    
}
std::cout << "Factorielle " << vFactorielle << " = " << vResultat << "\n";
Fin de l'exemple
Boucles DO WHILE

La différence entre une boucle while et une boucle do while est que dans la boucle "do while" le code inclus dans la boucle est exécuté au moins une fois.

Définition

Syntaxe :

do
{
    <ItérationCode>;
}while(<Condition>);

Voici un exemple d'implémentation qui montre que les instructions de la boucle "do while" sont bien executé au moins 1 fois.

Exemple
#include <iostream> // nécessaire pour utiliser "std::cout"

bool vContinuer = false; // limite de l'itération.
int vExecutionBoucle = 0;
do
{
    vExecutionBoucle++;
    std::cout << Boucle executée << vExecutionBoucle << " fois" << std::endl;
}
while(true == vContinuer);

std:cout << "Factorielle " << vFactorielle << " = " << vResultat << "\n";
Fin de l'exemple
Cet article est issu de Wikiversity. Le texte est sous licence Creative Commons - Attribution - Partage dans les Mêmes. Des conditions supplémentaires peuvent s'appliquer aux fichiers multimédias.