La conditionnelle


La programmation n'aurait que très peu d'intéret si elle ne permettait pas aux ordinateurs de réagir différemment selon différentes conditions.

Une machine programmable doit pouvoir effectuer des traitements différents selon les données qu'elle doit traiter.

Cela est possible grâce à l'existence des structures de controles dans les langages de programmation : la conditionnelle et les boucles.

L'objet de cette partie du cours est d'expliquer le fonctionnement d'une conditionnelle.

I - Le if

La conditionnelle if est une structure de contrôle permettant d'exécuter ou de ne pas exécuter certaines instructions en fonction de certaines conditions.

En francais, on peut la traduire par un si. Si telle condition est vérifiée alors exécuter telle action. C'est le If simple.

On peut également préciser ce qu'il faut faire lorsque la condition n'est pas réalisée: si telle condition est vérifiée alors exécuter telles instructions sinon exécuter telles instructions. C'est la structure Si ... Alors ... Sinon qui se traduit en C++ par un if suivi d'une partie else.

I-1 - Le if simple

Voici une manière d'écrire un if simple en C++:

if ( condition )
{
    Instructions à exécuter
    si la condition est vraie
}

La condition n'est rien d'autre qu'une expression logique.

Les instructions entre accolades ne seront exécutées que si la condition est vraie.

S'il n'y a qu'une seule instruction à exécuter, on peut omettre les accolades, mais cette instruction devra être suivie d'un point virgule :

if ( condition ) Instruction à exécuter ;

Prenons un exemple :

if ( n > 0 ) n-- ; 

Si par exemple n vaut 5 juste avant l'exécution du if, la condition n > 0 est vérifiée. L'ordinateur va donc exécuter l'instruction de décrémentation n-- . n vaudra donc 4 à la sortie de la conditionnelle.

Si n vaut -1 par contre, la condition n > 0 n'est pas vérifiée. L'affectation ne sera pas exécutée et n vaudra toujours -1 à la sortie de la conditionnelle.

I-2 - Le if avec partie else

Le if avec partie else permet d'exécuter certaines instructions si une condition est vraie et d'autres, si elle est fausse.

Voici une manière de l'écrire:

if ( condition )
{
    Instructions à exécuter
    si la condition est vraie
}
else
{
   Instructions à exécuter 
   si la condition est fausse 
}

De même, les accolades ne sont pas nécessaires s'il n'y a qu'une seule instruction.

Prenons un exemple :

if ( n > 0 )
   n--;
else
   n++;

Que se passe-t-il lors de l'exécution de cette conditionnelle ?

Supposons par exemple que n vale 5 juste avant l'exécution du if. La condition n > 0 est vérifiée. L'ordinateur va donc exécuter la décrémentation n--. Par contre, l'incrémentation n++ ne sera pas exécutée. n vaudra donc 4 à la sortie de la conditionnelle.

Si n vaut -1 par contre, la condition n > 0 n'est pas vérifiée. L'affectation n-- n'est donc pas exécutée. Mais comme la condition est fausse, l'affectation n++ sera exécutée. n vaudra donc 0 à la sortie de la conditionnelle.

I-3 - ifs imbriqués

Les instructions à l'intérieur d'un if ne sont pas forcément des affectations comme dans les exemples précédents.

On peut également y mettre d'autres structures de controle et en particulier d'autres ifs. En fait, pour le compilateur une structure de contrôle est une instruction. Gardez ceci à l'esprit. Cela vous permettra de comprendre les inévitables erreurs de compilation auxquelles vous serez confrontées.

Pour éclaircir les choses, prenons quelques exemples de ifs imbriqués.

Exemple 1
if ( n > 0 )
    n--;
else
    if ( n >= -3 )
         n++;
    else
         n = 2 * n;

Ce code doit être interprété de la manière suivante: si n est plus grand que zéro alors décrémenter n. Sinon, si n est supérieur ou égal à -3 incrémenter n, sinon multiplier n par 2.

Pour n=5 l'instruction exécutée est n--. n vaudra donc 4 à la sortie de la conditionnelle.

Pour n=-1 l'instruction exécutée est n++. n vaudra donc 0 à la sortie de la conditionnelle.

Pour n=-4 l'instruction exécutée est n = 2 * n. n vaudra donc -8 à la sortie de la conditionnelle.

De manière générale:

Exemple 2

Sans aucune règle ou convention, il est impossible de savoir si dans le code suivant:

if ( n > 0 )
    if ( n > 3 )
         n++;
    else
         n--;

le else se rapporte à la première condition (n > 0 ) ou à la deuxième (n > 3).

Dans le premier cas n-- serait exécutée pour tous les nombres inférieurs ou égaux à zéro, alors que dans le deuxième cas, cette instruction ne serait exécutée que pour les nombres 1, 2 et 3.

La règle utilisée par le compilateur C++ est la suivante:

Par défaut un else se rapporte au dernier if rencontré.

Dans le code précédent le else se rapporte donc à la condition (n > 3):

Exemple 3

Comment faire alors si l'interprétation du compilateur ne correspond pas à ce que l'on souhaite faire ?

La solution se trouve dans l'utilisation des accolades, car elles permettent de modifier l'interprétation du code par le compilateur.

Dans l'exemple précédent, si l'on souhaite que le else se rapporte à la première condition (n > 0), il suffit d'écrire les choses de cette manière:

if ( n > 0 )
    { if ( n > 3 ) n++; }
else
    n--;

En exécutant ce code, vous constaterez qu'il ne donne pas les mêmes résultats que celui de l'exemple 2:

II - Switch

La conditionnelle switch est utilisée lorsque l'on veut effectuer différents traitements selon la valeur d'une expression. La même chose peut être réalisée avec des ifs, mais en utilisant switch on obtient en général un code plus court.

Voilà la syntaxe d'un switch:

switch ( Expression ) 
{
       case V1 :
         Instructions à exécuter lorsque 
         l'expression vaut V1 ; break;
       case V2 :
         Instructions à exécuter lorsque 
         l'expression vaut V2 ; break;
       .
       .
       case VN :
         Instructions à exécuter lorsque 
         l'expression vaut VN ; break;
       default :
      Instructions à exécuter dans les autres cas ;  
}

L'expression entre parenthèses doit être d'un type numérique entier. Pour nous ce sera obligatoirement une expression de type int.

V1 , V2 , ...., VN sont des constantes qui doivent être de même type que l'expression. Dans notre cas, ce seront donc des nombres entiers.

La partie default est optionnelle.

break est une instruction qui permet de sortir de certaines structures de contrôle. En particulier, dans une structure de controle switch, son exécution provoque le saut systématique (on parle de branchement inconditionnel) à la première instruction qui suit la fin du switch.

Dans une structure de contrôle switch, l'instruction break est indispensable.

Voici, par exemple comment déterminer le nom d'un mois en fonction de son numéro avec une structure de contrôle switch:

 
switch ( NumeroMois  )
{
     case 1 : NomMois = "Janvier"; break;
     case 2 : NomMois = "Fevrier"; break;
     case 3 : NomMois = "Mars"; break;
     case 4 : NomMois = "Avril"; break; 
     case 5 : NomMois = "Mai"; break;  
     .
     .
     case 12 : NomMois = "Decembre"; break;     
     default :
       cout << "Numero de mois inexistant!";
}

Supposons par exemple que l'on ommette l'instruction break dans le troisième case:

 
switch ( NumeroMois  )
{
     case 1 : NomMois = "Janvier"; break;
     case 2 : NomMois = "Fevrier"; break;
     case 3 : NomMois = "Mars"; 
     case 4 : NomMois = "Avril"; break; 
     case 5 : NomMois = "Mai"; break;  
     .
     .
     case 12 : NomMois = "Decembre"; break;     
     default :
       cout << "Numero de mois inexistant!";
}

que se passera t-il ?

Tout ira bien, sauf lorsque le numéro du mois sera égal à 3. Dans ce cas l'ordinateur exécutera l'instruction NomMois = "Mars"; , mais comme elle n'est pas suivie d'un break, il continuera à exécuter le cas suivant, c'est à dire l'instruction NomMois = "Avril";. Au final, le résultat sera "Avril", lorsque le numéro du mois vaut 3.