Conditionnelles : erreurs classiques#
Nous allons maintenant voir quelques bonnes pratiques et erreurs classiques lorsque l’on utilise des instructions conditionnelles.
Exemple 1#
Dans cet exemple, on souhaite affecter à la variable estPositif
la
valeur «Vrai» si \(x \geq 0\) et «Faux» sinon. Cela se traduit
litéralement par :
int x = 4;
bool estPositif;
if ( x >= 0 ) {
estPositif = true;
} else {
estPositif = false;
}
estPositif
Mais ne pourrait-on pas faire mieux?
Si!
Grâce à George Boole qui a réalisé que «Vrai» et «Faux» sont des valeurs comme les autres avec lesquelles on peut calculer (expressions booléennes) et que l’on peut stocker (variables booléennes).
Exécutez les cellules ci-dessus et ci-dessous pour différentes valeurs
de x
et vérifier que le résultat est le même :
x = 4
x >= 0
bool estPositif = x >= 0;
estPositif
C’est plus concis. Plus efficace. Avec moins de risque d’erreur.
Pourquoi cela nous paraît-il moins naturel au premier abord? Parce
qu’il n’y a pas d’équivalent naturel dans la langue française! Au
mieux on peut utiliser une périphrase comme : stocker dans
estPositif
la valeur de vérité de l’expression «x est plus grand que
zéro».
Indication
À retenir Chaque fois que possible, utiliser une expression booléenne plutôtqu’une instruction conditionnelle.
Exemple 2#
Devinez le contenu de la variable y
à la fin de l’exécution du
programme suivant. Vérifiez en l’exécutant :
int x = 0;
int y = 0;
if ( x = 1 ) {
y = 4;
}
y
Pourtant x
n’est pas égal à 1! L’instruction y=4
n’aurait pas dû
être exécutée!?!
Sauf que … Nous avons utilisé une affectation =
et non un test
d’égalité ==
! Cela se voit à la valeur de x
:
x
Jupyter + Cling nous ont prévenus avec une alerte (warning) : ce n’est probablement pas ce que l’on souhaitait faire.
Il se trouve cependant que le code ci-dessus est valide en C++, ce qui est une cause classique de bogue.
Indication
Pour les curieux ♣
En toute logique le code ci-dessus devrait être invalide et déclencher une erreur. En effet, une affectation, c’est juste une instruction qui décrit une action à effectuer. Une action, cela n’a pas de valeur. Cependant de nombreux languages, dont C++, choisissent de faire de l’affectation une expression, en décidant de lui attribuer une valeur : celle qui a été affectée.
Cela permet par exemple d’affecter une valeur à deux variables simultanément :
x = y = 17
Analysez pourquoi cela marche, en l’interprétant sous la forme : x = ( y = 17 )
.
Maintenant nous savons que x = 1
est une expression qui vaut 1
tout le temps; elle est en particulier de type int
. Là encore le
code devrait être invalide puisque l’on a dit que if
prenait comme
condition une expression booléenne.
Sauf que … C++ hérite de C une vieille convention qui date de
l’époque où les languages n’avaient pas de type bool
. On
représentait alors les valeurs booléennes par des entiers, en
représentant «Faux» par 0
et «Vrai» par n’importe quel nombre entier
non nul. De ce fait l’expression x = 1
a pour valeur 1
qui est
interprétée comme «Vrai» dans le contexte d’une condition.
Exercice ♣
Quelles sont les valeurs de x
et y
à la fin du programme suivant :
int x = 1;
int y = 2;
if ( x = 0 ) {
y = 3;
}
Erreurs classiques avec les conditionnelles#
Devinez ce qu’affiche le programme suivant? Vérifiez en l’exécutant :
int x = 0;
int y = 0;
if ( x == 1 ); {
y = 4;
}
y
Ce programme est équivalent à :
if ( x == 1 );
y = 4;
qui ne tient pas compte du if
et affecte toujours 4
à y
(quel
que soit x
).
À retenir :
Le point-virgule
;
est un séparateur d’instruction;Le bloc d’instructions d’un
if
peut être vide en C++;Il ne faut jamais de point-virgule avant un bloc d’instructions!
Tests imbriqués#
Devinez ce qu’affiche le programme suivant? Vérifiez en l’exécutant :
int x = 5;
int y = 4;
std::string resultat = "";
if ( x >= y ) {
if ( x == y ) {
resultat = "égalité";
}
else {
resultat = "x est plus petit que y";
}
}
resultat
Oups. Il y a un bogue.
Explication : en C++, la structuration est entièrement déterminée par
les accolades : {
, }
. Les espaces et sauts de lignes ne jouent
aucun rôle. Aussi, ici, le else
se rapporte au deuxième if
,
contrairement à ce que la disposition visuelle du code pourrait faire
croire.
Maintenant, indentons correctement le code : c’est-à-dire décalons chaque ligne de quatre espaces par niveau d’imbrication dans des accolades :
resultat = "";
if ( x >= y ) {
if ( x == y ) {
resultat = "égalité";
}
else {
resultat = "x est plus petit que y";
}
}
resultat
La source du bogue est devenue claire, et on peut facilement le corriger :
resultat = "";
if ( x >= y ) {
if ( x == y ) {
resultat = "égalité";
}
} else {
resultat = "x est plus petit que y";
}
resultat
À retenir :
Un
else
se rapporte au dernierif
rencontré;En C++, la structuration est déterminée pas les accolades;
La mauvaise indentation induit en erreur le lecteur!
Apparté : l’indentation#
L” indentation (indentation) consiste à espacer les lignes de code par rapport au bord gauche de la fenêtre de saisie de texte;
L’espacement doit être proportionnel au niveau d’imbrication des instructions du programme;
Quatre espaces par niveau d’imbrication est un bon compromis.
La plupart des éditeurs de texte offrent des facilités pour réaliser une bonne indentation. Apprenez-les.
De la lisibilité des programmes#
«Programs must be written for people to read, and only incidentally for machines to execute.»
– Harold Abelson, Structure and Interpretation of Computer Programs 1984
Un programme s’adresse à un lecteur
La lisibilité est un objectif essentiel
Conclusion#
Nous avons vu les bonnes pratiques et erreurs classiques suivantes sur les instructions conditionnelles :
Bonne pratique : lorsque cela est possible, utiliser une expression booléenne plutôt qu’une instruction conditionnelle;
Erreur classique : insérer accidentellement une instruction vide
;
;Erreur classique : imbriquer incorrectement
if
etelse
.
Nous avons aussi vu l’importance de l”indentation pour la lisibilité des programmes.