Décider et répéter
Ce que ce chapitre apporte5 points
- Écrire une condition et enchaîner des cas avec if, else if, else.
- Distinguer = de ==, et reconnaître la faute que le langage laisse passer.
- Choisir entre while, for et do while selon ce qui est connu d'avance.
- Compter les tours d'une boucle sans se tromper d'une unité.
- Employer break et continue, et dire ce que chacun quitte.
Les structures de contrôle du C se retrouvent presque telles quelles dans une bonne moitié des langages qui existent : le if, le while, le for à trois parties, les accolades, le break. Ce n'est pas un hasard de vocabulaire, c'est un héritage direct, et savoir les lire ici revient à savoir les lire en Java, en C++, en C# ou en JavaScript.
Ce chapitre les installe, et s'arrête surtout sur ce que le langage accepte sans broncher : une affectation là où une comparaison était voulue, une boucle dont la condition ne progresse pas, un else qui ne se rattache pas au if qu'on croit. Trois fautes qui ne produisent aucun message, et qui expliquent pourquoi les accolades sont une discipline avant d'être une syntaxe.
Décider
Une condition est une expression entière : zéro vaut faux, tout le reste vaut vrai. Il n'existe pas de type booléen dans le C d'origine, et ce détail explique une bonne part des surprises.
La dernière ligne montre le fond de l'affaire : 21 est une condition parfaitement valide, et elle
est vraie, parce qu'elle n'est pas nulle.
if (x = 5) est une instruction valide. Elle range 5 dans x, puis évalue le résultat de cette affectation, qui vaut 5, donc qui est vrai. La branche est toujours prise, et x a été modifiée au passage.Aucune erreur, aucun avertissement par défaut. C'est la faute qui a fait perdre le plus d'heures dans l'histoire de ce langage, et la parade tient en une habitude : relire à voix haute « si x vaut cinq » et vérifier qu'il y a bien deux signes égal sous les yeux.
temperature > 30 par temperature = 30 et relancer. Le programme annonce « chaud » alors que la température était de 21 degrés, et la variable vaut maintenant 30 pour la suite du programme.Remettre ensuite
== : le programme annonce « tempere », parce que 21 n'est pas égal à 30. Deux caractères séparent les deux comportements, et rien dans la page ne les distingue au premier coup d'œil.
Répéter tant que
while évalue sa condition avant chaque tour. Si elle est fausse au départ, le corps n'est jamais
exécuté.
Le reste final est négatif, et c'est normal : la condition est vérifiée avant le tour, pas pendant.
Un programme qui doit s'arrêter exactement à zéro ne se contente pas de cette boucle, il ajuste le
dernier pas.
L'interpréteur de ces pages s'arrête au bout de trois millions d'opérations et le dit. Un vrai programme, lui, tournerait jusqu'à ce que quelqu'un l'interrompe.
Répéter un nombre connu de fois
for rassemble au même endroit les trois choses qui gouvernent une boucle de comptage :
l'initialisation, la condition, et le pas.
Les deux boucles ci-dessus font chacune un nombre de tours différent de ce que les nombres écrits laissent croire, et c'est le seul point à retenir vraiment.
| Boucle | Premier tour | Dernier tour | Nombre de tours |
|---|---|---|---|
for (i = 1; i <= 10; i++) | 1 | 10 | 10 |
for (i = 0; i < 10; i++) | 0 | 9 | 10 |
for (i = 0; i <= 10; i++) | 0 | 10 | 11 |
for (i = 1; i < 10; i++) | 1 | 9 | 9 |
for (int i = 0; i < n; i++) fait exactement n tours, avec i allant de 0 à n moins 1.Ce n'est pas une convention esthétique : c'est la numérotation des cases d'un tableau, qui commence à zéro et finit à n moins 1. Écrire ses boucles ainsi évite d'avoir à convertir au moment où le tableau arrive, au chapitre suivant.
Répéter au moins une fois
do while évalue sa condition après le tour. Le corps est donc exécuté au moins une fois, ce qui
convient quand la condition porte sur quelque chose que le tour produit.
Écrite avec un while ordinaire, cette boucle donnerait zéro chiffre pour le nombre 0, qui en compte
pourtant un. La forme do while répond correctement parce qu'elle divise avant de tester.
Sortir, ou sauter un tour
break quitte la boucle entière. continue abandonne le tour en cours et passe au suivant.
Ce programme affiche les nombres premiers jusqu'à trente. Le break quitte la recherche de diviseur
dès qu'un diviseur est trouvé, parce que continuer ne changerait plus la réponse ; le continue
passe au nombre suivant sans l'afficher. La condition d * d <= n arrête la recherche à la racine
carrée, ce qui suffit : un diviseur plus grand que la racine en a forcément un plus petit en face.
d * d <= n par d < n : le résultat est le même, et le nombre de tours bien plus grand. Remplacer ensuite par d <= n : la boucle trouve n comme diviseur de lui-même, plus aucun nombre n'est premier, et rien ne s'affiche.Le troisième essai est le plus instructif : la sortie vide n'est pas une panne, c'est une réponse fausse produite par une condition d'arrêt fausse.
À calculer soi-même
Une boucle se compte avant d'être écrite.
Compter les tours
- 1.
Combien de tours fait for (int i = 0; i < 25; i++) ?
- 2.
Combien de tours fait for (int i = 1; i <= 25; i++) ?
- 3.
Combien de tours fait for (int i = 0; i <= 25; i++) ?
- 4.
Combien de tours fait for (int i = 5; i < 50; i += 5) ?
- 5.
Après while (reste > 0) { reste = reste - 15; } parti de 100, combien de tours ont eu lieu ?
- 6.
Après cette même boucle, que vaut reste ?
- 7.
Un nombre de 4 chiffres, divisé par 10 jusqu'à devenir nul : combien de divisions ?
Vérification
1.Que fait if (x = 5) { ... } ?
2.Combien de tours fait for (int i = 0; i <= 10; i++) ?
3.Quelle est la différence entre while et do while ?
4.Que quitte un break placé dans une boucle imbriquée dans une autre ?
5.Qu'est-ce qu'une condition vraie en C ?
Exercices type
Pourquoi mettre des accolades même autour d'une seule instruction ?
Parce que sans elles, seule la première instruction appartient à la branche ou à la boucle, et que l'indentation ne change rien à cette règle. Le C ignore les espaces, contrairement à Python.
Le cas est célèbre : une branche de sécurité écrite sans accolades, à laquelle une ligne a été ajoutée plus tard, a produit une faille dans une bibliothèque de chiffrement très répandue. La ligne ajoutée s'exécutait toujours, quelle que soit la condition.
Les accolades systématiques coûtent deux caractères et suppriment cette classe entière de fautes.
Comment écrire une boucle qui parcourt les valeurs de 10 à 1, en descendant ?
for (int i = 10; i >= 1; i--) { ... }
Trois choses changent ensemble : la valeur de départ, le sens de la comparaison, et le pas. Changer le pas sans changer la comparaison donne une boucle qui ne fait aucun tour, ou qui n'en finit pas, selon le sens.
Le contrôle qui vaut la peine consiste à se demander, avant d'exécuter : quelle est la première valeur, quelle est la dernière, et combien y en a-t-il.
Un programme doit s'arrêter dès qu'une valeur négative est lue parmi cent mesures. Quelle structure choisir ?
Un for sur les cent mesures, avec un break dès qu'une valeur négative apparaît. Le for porte le
nombre maximal de tours, le break porte la condition d'arrêt anticipé, et les deux restent lisibles
séparément.
L'autre écriture, un while avec une condition composée, mélange les deux raisons de s'arrêter dans
une seule expression, et c'est elle qui produit les conditions d'arrêt fausses.
La méthode
- Écrire les accolades, même pour une seule instruction, et même quand personne ne regarde.
- Relire chaque
=dans une condition, et vérifier qu'il en faut bien deux. - Choisir la boucle d'après ce qui est connu :
forquand le nombre de tours est connu d'avance,whilequand il dépend de ce qui se passe,do whilequand un tour au moins est certain. - Compter les tours avant d'exécuter : première valeur, dernière valeur, nombre de tours.
- Vérifier que la variable de la condition progresse dans tous les chemins du corps,
continuecompris.
Synthèse
- Une condition est un entier : zéro est faux, tout le reste est vrai.
=affecte,==compare. L'affectation dans une condition est valide, et toujours vraie quand la valeur affectée n'est pas nulle.for (int i = 0; i < n; i++)fait exactement n tours, avecide 0 à n moins 1.whileteste avant,do whileteste après et exécute donc au moins un tour.breakquitte la boucle qui le contient directement ;continuepasse au tour suivant.
Et ensuite
Le code écrit jusqu'ici tient dans une seule fonction. Les fonctions et la pile le découpe, et montre où vivent les variables locales : un endroit de la mémoire qui se vide tout seul, et dont il ne faut rien rapporter.
Mettre en pratique
Compter les tours d'une boucle, le signe égal de trop, et la condition d'arrêt qui ne progresse pas.
- Compter les tours d'une boucleNiveau 1
- La boucle qui dépasse d'une caseNiveau 2
- Compter les chiffres par divisionsNiveau 2