Instruction de redirection multiple switch

Nous avons vu que, lorsqu’on devait choisir entre deux possibilités, on utilisait une instruction de branchement if...else. Il existe une autre instruction de branchement, nommée switch, dont la syntaxe est la suivante :

switch (expression) {
              case constante1 : instructions1;
              case constante2 : instructions2;
              ............................
              case constanteN : instructionsN;
              default : instructions0;
              }

L’expression expression est évaluée (elle doit être d’un type numérique), puis comparée à constante1, constante2, etc., jusqu’à ce qu’une identité soit trouvée ; dans ce cas, les instructions qui suivent (il peut y en avoir plusieurs) sont exécutées, jusqu’à l’accolade fermante finale, et non jusqu’à l’instruction case suivante. Si aucune des constantes n’est égale à l’expression, ce sont les instructions qui suivent default qui sont exécutées. Cette dernière clause est semblable au else du branchement simple, et peut également être omise.

Il est important de noter que toutes les instructions suivant la constante qui coïncide avec l’expression sont exécutées. Ainsi, si l’on écrit :

switch (i) {
              case 1 : i = 0;
              case 2 : i = 10;  // probablement erroné
              default i++;
              }

la variable i sera mise à 11 si elle valait 1 ou 2 au départ, sinon elle sera incrémentée. En effet, si i vaut 1 au départ, les trois instructions i = 0; i = 10; i++; sont exécutées à la suite.

Dans ce cas, il s’agit certainement d’une erreur. Pour la corriger, on utilise l’instruction d’interruption break, qui interrompt la circulation dans l’instruction de branchement, passant directement à celle qui suit l’accolade fermante :

switch (i) {
              case 1 : i = 0; break;
              case 2 : i = 10; break;
              default i++;
              }

Ici, on a bien le comportement imaginé. Cette utilisation de break dans une instruction switch est extrêmement fréquente ; il est important de ne pas l’oublier.

Dans certains cas cependant on ne souhaite pas placer de break derrière certaines constantes, en particulier lorsqu’il y en a plusieurs. Voici par exemple une fonction qui remplace dans une chaîne les caractères accentués par leur équivalent sans accent :

char *sansaccent(char *chaine)
{
    for (char *s = chaine; *s; s++)
    switch (*s) {
        case 'à':; case 'â':;    // continuer...
        case 'ä': *s = 'a'; break;       // ... ici
        case 'é':; case 'è':; case 'ê':;    // idem
        case 'ë': *s = 'e'; break;
        case 'ì':; case 'î':;    // idem
        case 'ï': *s = 'i'; break;
        case 'ô':; case 'ò':;    // idem
        case 'ö': *s = 'o'; break;
        case 'ù':; case 'ü':;     // idem
        case 'û': *s = 'u'; break;
        case 'ÿ': *s = 'y'; break;
    }
    return chaine;
}

Seules les minuscules ont été traitées ; le lecteur étendra sans peine la méthode aux majuscules. On notera le point-virgule obligatoire entre le deux-points et le case suivant, même s’il n’y a pas d’instruction. Il n’y a pas ici de clause default, puisqu’il n’y a pas d’action si le caractère n’est pas accentué.

L’écriture d’un branchement multiple n’est pas toujours la meilleure méthode. Il est parfois préférable d’utiliser des systèmes plus rapides. Ainsi, dans notre exemple, un tableau de correspondance des caractères initialisé une fois pour toutes aurait permis un traitement plus expéditif.

Dans certains cas, il est franchement impossible d’utiliser une instruction switch, parce qu’elle serait trop pénible à écrire. Ainsi, la fonction toupper de la librairie <ctype.h>, qui transforme un caractère en la majuscule correspondante, devrait être écrite avec un switch :

char toupper(char c)
     {
         switch (c) {
             case 'a' : return 'A';
             case 'b' : return 'B';
             // etc...
             case 'z' : return 'Z';
             default  : return c;
             }
     }

Il s’agit évidemment d’une écriture bien trop longue. On notera toutefois deux points importants à son sujet. Tout d’abord, le fait d’écrire une instruction return nous dispense d’écrire un break, puisque cela termine directement la fonction. D’autre part, il s’agit d’une situation typique où le compilateur ne peut pas savoir si tous les cas ont été traités ou non ; en conséquence, si l’on oublie la clause default ici essentielle, la fonction retournera une valeur aléatoire si son argument n’était pas une minuscule (c’est d’ailleurs le comportement de la variante _toupper de cette fonction).

Exercice 4.1

Comment programmer plus facilement cette fonction, sans utiliser switch ?

Voir solution

Enfin, il ne faut pas tenter d’utiliser switch pour des intervalles de nombres, puisqu’on ne peut pas placer une condition derrière case ; pour la même raison, il vaut mieux ne pas l’utiliser avec des décimaux.

Les mots switch, case et default sont réservés en C++.

Précédent Précédent Sommaire Sommaire Suivant Suivant