Chapitre 8 Structure de contrôle
Chapitre 8: Sujets Introduction Instructions de sélections Instructions d'itérations Branchements inconditionnels Branchements conditionnels Conclusions 2
Niveaux de flot de contrôle Dans les expressions (chapitre 7) Entre les différentes unités du programme (chapitres 9 et 10) Entre les instructions
Instructions de contrôle: Évolution Années 50: FORTRAN I: Directement liées à l'architecture du IBM 704 if et goto Années 60: Résultat important: Il est prouvé que tout algorithme exprimé par un organigramme peut être encodé dans un langage possédant seulement 2 instructions de contrôle: instruction pour choisir entre deux flots de contrôle instruction pour le contrôle logique d'un processus itératif Conclusion: Le goto est utile mais non essentiel La lisibilité et la facilité d'écriture impose l'utilisation de plus de 2 instructions de contrôle
Structure de contrôle Une structure de contrôle est une instruction controlant l'exécution d'un groupe d'instructions Choix de conception Une structure de contrôle devrait-elle avoir plusieurs points d'entrées? Possible en présence de goto et d'étiquettes d'instructions. Points de sorties? Pas de problème si l'instruction de sortie est fixe Exemple: Utilisation du break dans un switch en C Sinon, la situation est équivalente à utiliser un goto
Instructions de sélection Une instruction de sélection permet de choisir entre deux ou plusieurs flots Deux catégories générales: Deux choix Plusieurs choix
Instruction de sélection à deux choix Forme générale: if expression_controle then clause else clause Choix de conception: Quel est la forme et le type de l'expression de contrôle? Comment les clauses then et else sont-elles spécifiées? Comment spécifier la sémantique des sélecteurs imbriqués?
Sélection à un seul choix:Exemples FORTRAN: IF (expr_booleenne) énoncé Problème: On ne peut choisir qu'un seul énoncé; pour en choisir plus, on doit utiliser un goto IF (.NOT. condition) GOTO 20 ... GOTO 30 20 CONTINUE 30 ... L'utilisation de négations nuit à la lisibilité Ce problème fut résolu dans FORTRAN 77
Sélection à deux choix: Exemples ALGOL 60: if (boolean_expr) then instruction) else instruction Les instructions peuvent être simples ou composées.
Sélecteurs imbriqués Java: exemple if (sum == 0) if (count == 0) result = 0; else result = 1; À quel if appartient le else? La sémantique en Java est la suivante: le else correspond au if le plus près Note: Il s'agit du problème d'ambiguïté rencontré avec les grammaires hors- contextes.
Sélecteurs imbriqués (suite) Pour forcer une sémantique alternative, on doit utiliser les instructions composées: if (sum == 0) { if (count == 0) result = 0; } else result = 1; Cette solution est utilisée en C, C++, JavaScript, PHP et C# En Perl elles sont toujours composées La fin du if peut aussi être indiquée par un mot réservé: end if en Ada End If en Fortran et Visual basic end en Ruby et Lua Indentation en Python
Sélections multiples On choisit parmi un nombre arbitraire d'instructions Choix de conception: Quel est la forme et le type de l'expresion de contrôle? Comment spécifier les différentes sélections? Une sélection est un des segment de code faisant l'objet de la sélection Le flot de contrôle est-il restreint à une seule sélection? Que fait-on avec les expressions non représentées par l'ensemble des sélection possibles?
Sélections multiples: Exemple Sélecteur multiple: FORTRAN: arithmetic IF (sélecteur à 3 choix) IF (expression arithmetique) N1, N2, N3 N1, N2 et N3 sont des étiquettes Le flot de contrôle va à: N1 si <0 N2 si =0 N3 si >0
Sélections multiples: Exemples Sélections multiples modernes: L'instruction switch en C switch (expression) { case const_expr_1: stmt_1; … case const_expr_n: stmt_n; [default: stmt_{n+1}] }
Sélections multiples: Exemples Choix de conception pour le switch: L'expression de contrôle doit être un type entier Plusieurs sélections peuvent être exécutées (il n'y a pas de branchement implicite à la fin d'une sélection) la clause default sert à représenter les choix manquants (en l'absence de default, ces choix sont ignorés)
Sélections multiples: Exemples L'instruction switch en C#: Comme en C sauf que l'on est obligé de mettre un break (ou un goto) après chaque sélection.
Sélections multiples: Exemples L'instruction case en Ada case expression is when liste de choix => instructions; … [when others => instructions;] end case; Liste de choix: 10..15 ou 10|15|20 Les listes de choix doivent être exhautives Les listes de choix doivent être disjointes Sortie implicite après toutes les listes d'instructions Plus fiable que le switch du C
Sélections multiples: Exemples L'instruction case en Ruby (1ière forme): bisextile = case when annee%400==0 then true when annee%100==0 then false else annee%4==0 end
Sélections multiples: Exemples L'instruction case en Ruby (2ième forme): case expression when valeur then instructions [else instructions] end
Sélections multiples: avec le if Exemple en Ada: if ... then ... elsif ... else ... end if
Les instructions d'itération L'exécution répétée d'instructions est accomplie par la récursion ou par itération. Choix de conception générale: 1. Comment contrôler un processus itératif? 2. Où placer le mécanisme de contrôle?
Boucles à compteur La boucle est contrôlée par un compteur Les paramètres de la boucle sont: La valeur initiale du compteur La valeur finale du compteur L'incrément du compteur
Boucles à compteur (suite) Choix de conception: Quel est le type et la portée du compteur? Quelle est la valeur du compteur au sortir de la boucle? Peut-on changer la valeur du compteur et les paramètres de la boucle à l'intérieur du corps de la boucle? Si oui, comment cela affecte-t-il le contrôle de la boucle? Les paramètres de la boucle doivent-ils être évalués une seule fois ou avant chaque itération?
Instructions d'itération: Exemples Syntaxe du FORTRAN 90 DO étiquette var = début, fin [, increment] L'incrément est n'importe quelle valeur sauf 0 (la valeur de défaut est 1) Les paramètres peuvent être des expressions Exemple: Do 10 Index = 1, 100 ... 10 Continue
Instructions d'itération: Exemples Choix de conception: Le compteur doit être de type INTEGER Au sortir de la boucle, le compteur conserve la dernière valeur qui lui a été affectée. Le compteur ne peut pas être modifié à l'intérieur du corps de la boucle. Les paramètres peuvent être changés sans affecter le contrôle der la boucle (ils sont évalués une seule fois)
Instructions d'itération: Exemples Autre forme du DO en FORTRAN 95 : [nom:] DO var = initial, terminal [,incrément] ... END DO [nom] Le compteur doit être de type INTEGER
Instructions d'itération: Exemples L'instruction for en Pascal for variable := initial (to|downto) final do instruction Choix de conception: Le compteur doit être de type ordinal Au sortir de la boucle, la valeur du compteur est indéfinie Le compteur ne peut pas être modifié dans la boucle. Les paramètres sont évalués juste une fois: il peuvent donc être changés sans affecter le contrôle
Instructions d'itération: Exemples Ada for var in [reverse] intervalle loop ... end loop intervalle d'entiers (1..n) ou enumération (lundi.. vendredi) Le compteur est déclaré implicitement et ne peut être modifié. Les paramètres sont évalué juste une fois. La portée et la duré de vie du compteur se limite à la boucle.
Instructions d'itération: Exemples L'instruction for en C for ([expr_1] ; [expr_2] ; [expr_3]) instruction N'importe quel type d'expressions est permis. En particulier on peut utiliser une séquence d'expressions séparées par des virgules. La valeur de expr1, expr2, ..., exprn est exprn Il n'y a pas nécessairement de compteur explicite for (nbcar=0; getchar()!=EOF; nbcar++); Tous les paramètres peuvent être changés dans la boucle La première expression est évaluée une seule fois, les autres à chaque itération.
Instructions d'itération: Exemples C++ diffère du C de deux façons: L'expression de contrôle peut être booléenne L'expression initiale peut contenir des définitions (la portée est limitée à la boucle) Java et C# L'expression de contrôle doit être booléenne.
Instructions d'itération: Exemples Python: for <variable> in <objet>: <corps de la boucle> [else <code de fin de boucle> ] Exemple 1: for X in [2, 4, 6]: print X Exemple 2 for Y in range(2,100,2): print Y
Boucles contrôlée logiquement La boucle est contrôlée par une expression logique Choix de conception: Pré-test ou post-test? Est-ce que ce type de boucle est une forme particulière des boucles à compteur ou une instruction séparée? Formes générales en C et C++: while (expr_logique) do instruction instruction while (expr_logique)
Boucles contrôlée logiquement Exemple Pascal utilise deux formes distinctes de boucles (while-do et repeat-until) Java est comme le C, sauf que l'expresison de contrôle doit être de type booléen De plus, en Java, on ne peut entrer dans le corps d'une boucle que par le début car Java n'a pas d'instruction goto.
Boucles contrôlée logiquement Exemple Ada possèdent une version pré-test mais aucune post-test FORTRAN 77 et 90 n'ont aucune des deux versions Perl possède deux boucles pré-test, while et until, mais aucune post-test Python possède une version pré-test (while)
Boucle avec contrôle de sortie placé par l'usager Il est quelque fois utile de pouvoir contrôler une boucle ailleurs qu'au début ou à la fin Conception simple pour les boucles simples (e.g., break) Choix de conception pour les boucles imbriquées: Peut-on sortir de plus d'une boucle à la fois?
break et continue C , C++, Python, Ruby et Java: instruction break Fonctionne dans n'importe quelle boucle ou switch (un seul niveau) Java et C# possèdent une instruction break <etiquette> qui transfère le contrôle après la boucle portant l'étiquette. Perl: instruction last équivalente à break dans Java Alternative: instruction continue; saute par dessus le reste du code mais ne quitte pas la boucle.
Exemple en Java Le code suivant fait la somme des éléments d'une matrice et arrête aussitôt que cette somme dépasse 1000. Debut: for (i=0; i<nblignes; i++) for (j=0; j<nbcol; j++){ somme += MAT[i][j] if (somme > 1000.0) break Debut; }
Exemple en Ada Ada possède un mécanisme similaire: NOM: loop énoncés exit NOM when condition end loop
Itérations et structures de données Le nombre d'éléments dans une structure de données contrôle le nombre d'itérations Le mécanisme de contrôle est aussi appelé itérateur. Un itérateur est une fonction permetant d'obtenir le prochain élément, s'il existe, sinon la boucle se termine. Un itérateur peut être construit en C: for (p=root; p==NULL; traverse(p)){...} L'utilisation des itérateurs est courante dans les langages orienté-objet tels que C++ et Java
Itérations et structures de données PHP: Les itérateurs sur les tableaux sont prédéfinis: reset $list print(current($list) + "<br />"); while ($valeur = next($list)) print($valeur + "<br />");
Itérations et structures de données L'instruction foreach de C# permet d'itérer sur les éléments d'un tableau ou autres collections: Strings[] Liste = {“Bob”, “Carol”, “Ted”}; foreach (Strings nom in Liste) Console.WriteLine (“Nom: {0}”, nom); La notation {0} indique la position du paramètre (nom) que l'on veut afficher
Branchement inconditionnel Tranfère le contrôle à un emplacement quelconque du programme. Sujet d'un des plus vigoureux débats des années 60 et 70 Puissant et flexible Principal problème: Lisibilité Certains langages ne supportent pas le goto (e.g., Modula-2 et Java) Les instructions tels que break et continue sont des formes restreintes de goto.
Branchement inconditionnel C# possède une instruction goto qui est principalement utilisée avec le switch: switch (valeur){ case -1: negatif++; break; case 0: zero++; goto case 1; case 1: positif++ default: Console.WriteLine("Error dans le switch \n"); }