Structures itératives en Pascal
Un article de Mangue.org, l'encyclopéde libre.
Les structures itératives vont vous permettre de répéter plusieurs fois un traitement de manière élégante.
| Sommaire |
repeat - until
Reprenons le programme que nous avons écrit à la fin du [./cours7.htm cours précédent], celui-ci permettait de résoudre un trinôme :
program Trinome;
(* uses WinCrt; *)
label Entrees;
var A, B, C : real; (* coefficients *)
Delta : real; (* discriminant *)
(**** Debut du programme ****)
begin
Entrees: (* entrees utilisateur *)
writeln ('Resolution d''un trinome Ax²+Bx+C=0');
write ('Entrez les coefficients A, B et C : ');
readln ( A, B, C);
(* verification des entrees *)
if ( A = 0.0) then
begin
writeln ( 'A doit etre non nul !');
goto Entrees
end;
(* traitement des donnes *)
Delta := B*B - 4*A*C;
(* sorties *)
if ( Delta < 0.0) then
writeln('Le trinome a deux solutions complexes')
else if ( Delta = 0.0) then
writeln('Le trinome a une solution reelle')
else
writeln('Le trinome a deux solutions reelles');
readln (* pause *)
end.
Dans ce programme nous répétions la demande des coefficiants de notre trinôme jusqu'à ce que la valeur de A soit non nulle.
Nous avons implémenté celà grace à un label et une condition puisqu'il s'agit de la seule méthode que nous connaissions alors. Mais ce n'est pas la meilleure solution, il est préférable d'utiliser une structure itérative qui assure elle même la répétition du traitement en fonction d'une condition.
Dans notre exemple il s'agit d'effectuer le traitement jusqu'à ce que A soit non nul. Il existe justement une structure itérative repeat - until permettant de faire un traitement et éventuellement de le répéter si la condition de l'itération n'est pas vérifiée.
Mais plutôt que de vous noyer sous des explications, analysez plutôt cet exemple qui remplacera notre programme :
program Trinome;
(* uses WinCrt; *)
var A, B, C : real; (* coefficients *)
Delta : real; (* discriminant *)
(**** Debut du programme ****)
begin
(* entrees utilisateur *)
writeln ('Resolution d''un trinome Ax²+Bx+C=0');
repeat
write ('Entrez les coefficients A, B et C avec A non nul ! ');
readln ( A, B, C)
(* verification des entrees *)
until ( A <> 0.0)
(* traitement des donnes *)
Delta := B*B - 4*A*C;
(* sorties *)
if ( Delta < 0.0) then
writeln('Le trinome a deux solutions complexes')
else if ( Delta = 0.0) then
writeln('Le trinome a une solution reelle')
else
writeln('Le trinome a deux solutions reelles');
readln (* pause *)
end.
La syntaxe est assez intuitive, le repeat marque le début du bloc d'itération qui est alors terminé par l'apparition du mot clé until et de sa condition biensûr.
Encore une fois même si ce n'est pas nécessaire je place la condition entre parenthèses ;-)
| Remarque |
Le smots clé repeat et until délimitent à eux seuls un bloc. C'est pourquoi vous ne voyez pas apparaître de begin - end à l'intérieur de ceux-cis.
|
Dans un bloc repeat - until, l'évaluation de la condition d'itération se fait à la fin de la boucle, c'est pourquoi le tout sera exécuté au moins une fois quoi qu'il arrive !
Essayez donc de compiler et d'exécuter ce programme si vous n'en êtes pas convaincu, la condition est fausse bien évidemment mais le traitement a bien été effectué !
program DemonstrationDeLInterpretationDuRepeatUntil;
(* uses WinCrt; *)
begin
repeat
write('Cette condition est fausse')
until (3 < 1)
end.
while - do
Comment procéder alors si on ne souhaite pas que l'itération soit traitée à tous les coups. Dans la plus part des programmes, le traitement devra ne pas être exécuté du tout si la condition d'itération est fausse !
Heureusement pour nous en Pascal il existe une structure while - do effectuant le même type d'itérations qu'un repeat - until à ceci près que la condition d'itération est justement évaluée en début de boucle.
Voici déjà une exemple d'utilisation de cette structure. Dans le programme qui suit nous demandons à l'utilsateur de fournir un nombre entier positif, ensuite nous lançons un compte à rebours de ce nombre jusqu'à 0 forcément ;-)
program CompteARebours;
(* uses WinCrt; *)
(* constantes du programme *)
const CrLf = chr(10) + chr(13); (* retour chariot *)
(* declaration des variables *)
var Nombre : integer;
(* debut du programme *)
begin
(* entrees utilisateur *)
write( CrLf, 'Entrez un nombre entier positif : ');
readln( Nombre);
(* 2 lignes vides *)
writeln( CrLf);
(* sorties ecran *)
while ( Nombre >= 0) do
begin
writeln ( Nombre);
dec ( Nombre) (* Nombre := Nombre - 1 *)
end;
(* pause *)
readln
end.
Le programme nous affiche un joli petit compte à rebours si la condition initiale est vrai ; en revanche il n'affiche rien si la condition était fausse à son arrivée sur le while (Nombre <= 0) c'est à dire si l'utilisateur a fournit un nombre négatif en entrée.
| Danger |
Ne faites pas l'erreur de confondre une itération de type while à une itération de type repeat.La première ne boucle que sur une seule instruction alors que la seconde applique l'itération sur un bloc d'instructions. Ainsi si vous voulez construire une itération avec plusieurs instructions pour un while vous devrez penser à utiliser un bloc begin - end
|
Un petit exercice vous permettra d'ores et déjà de manipuler les itérations. Je vous propose d'écrire un programme qui affiche l'alphabet en utilisant une itération (plusieurs solutions sont possibles).
Pensez à utiliser les fonctions inc et dec qui permettent d'incrémenter et décrémenter des entiers biensûr, mais aussi des caractères !
program Alphabet;
(* une solution possible *)
(* uses WinCrt; *)
(* declaration des variables *)
var Lettre : char;
(* debut du programme *)
begin
(* initialisation *)
Lettre := 'A';
(* saute une ligne *)
writeln;
(* affichage de l'alphabet *)
while ( Lettre <= 'Z') do
begin
write ( Lettre);
inc ( Lettre)
end;
(* pause *)
readln
end.
Encore un exercice... Cette fois je vous demanderai simplement de calculer la factorielle d'un nombre entier entré par l'utilisateur.
| Remarque |
Rappel mathématique : La factorielle d'un nombre entier N positif est la multiplication entre eux de tous les nombres compris entre 1 et N.On prend comme convention que la factorielle de 0 notée 0! et lu factorielle 0 est égale à 1On peut également démontrer que N! = N * (N-1)!
|
program Factorielle;
(* uses WinCrt; *)
(* declaration des variables *)
var Nombre : integer; (* argument *)
Temp : integer; (* utile pour le calcul *)
Fact : integer; (* factorielle *)
begin
writeln;
(* entrees *)
repeat
write ( 'Argument : ');
readln ( Nombre)
until ( Nombre >= 0)
(* initialisation *)
Fact := 1;
Temp := Nombre;
(* calcul *)
while ( Temp > 1) do
begin
Fact := Fact * Temp;
dec ( Temp)
end;
(* sorties *)
writeln;
write(Nombre,' a pour factorielle : ', Fact);
readln (* pause *)
end.
Vous devriez être capable d'expliquer vous même ce qu'il arrive pour le calcul d'une factorielle supérieure à 7. Un overflow apparaît, pour l'éviter on pourrait tout simplement interdire le calcul de ces factorielles ou alors changer de type d'entier afin de permettre le codage dans l'ordinateur de nombres plus grands.
for - to/downto - do
Dans la plus part des exemples que nous avons u jusqu'à présent nous faisions intervenir des incrémentations ou des décrémentations à chaque itération. Ce genre de traitement est fréquent, de plus lorsque la condition d'itération dépend elle même ce cette incrémentation (ou décrémentation) on peut remplacer la struture while concernée par un boucle de type for
Vous convinedrez que si une boucle est écrite avec ce procédé la lisibilité en sera accrue ! Vous en doutez encore ? Regardez ce que devient le programme CompteARebours :
program CompteARebours;
(* uses WinCrt; *)
(* constantes du programme *)
const CrLf = chr(10) + chr(13); (* retour chariot *)
(* declaration des variables *)
var Nombre : integer;
Temp : integer;
(* debut du programme *)
begin
(* entrees utilisateur *)
write( CrLf, 'Entrez un nombre entier positif : ');
readln( Nombre);
(* 2 lignes vides *)
writeln( CrLf);
(* sorties ecran *)
for Temp := Nombre downto 0 do (* ligne 22 *)
writeln ( Temp);
(* pause *)
readln
end.
Une boucle for fera nécessairement intervenir une variable de contrôle qui sera intialisée au sein même de la structure. Vous devrez enfin fournier une valeur limite qui permettra de déterminer quand mettre fin aux itérations et enfin un mot clé permettant de savoir si on incrément ou décrémente entre chaque itération (donc to ou downto repectivement)
Lorsque le compilateur arrive sur une instruction telle que celle-ci il commence par affecter la valeur initiale à notre variable de contrôle (donc ici Temp := Nombre), il compare ensuite cette valeur à la valeur finale en fonction du type de pas demandé (incrémentation ou décrémentation), si le traitement peut être effectué en fonction du résultat de cette comparaison pas de problèmes ! Sinon le traitement n'a plus lieu.
De plus si vous essayiez par exemple d'incrémenter votre variable de contrôle de 4 (valeur initiale) à 2 (valeur finale) et bien rien ne se passerait ! On sauterait simplement la structure itérative !
Dans tous les cas et quelque soit le traitement, il est possible de rammener une boucle for à une boucle while.
| Danger |
| Il est important de veiller à ce que la valeur de votre variable de contrôle ne soit pas modifiée par les instructions de l'itération. Si votre programme est bien construit, la valeur de cette variable ne doit pas être modifiée d'une autre manière qu'avec les incrémentations/décrémentations programmées par la boucle for elle même !
|
| Remarque |
| Contrairement à d'autres langages il est impossible en Pascal de spécifier le pas d'une incrémentation/décrémentation. Impossible donc d'aller de la valeur initiale à la valeur finale en ajoutant 5 à chaque fois par exemple ! |
Je vous propose un exercice simple. L'utilisateur entre un nombre entier et vous devez lui afficher la table de multiplication de ce nombre ! Voici une correction possible :
program Tables;
(* uses WinCrt; *)
const Maximum = 10;
(* declaration des variables *)
var Nombre : byte; (* entier de 0 à 255 *)
I : byte;
(**** debut du programme ****)
begin
writeln;
(* entrees *)
repeat
write('Vous voulez la table de ? ');
readln(Nombre)
until ( (Nombre > 1) and (Nombre <= 255));
(* affichage *)
writeln; (* saute une ligne *)
for I := 1 to Maximum do
begin
write(I:3, ' * ', Nombre:3);
writeln(' = ', (I*Nombre):7)
end;
readln (* pause *)
end.
boucles infinies
Même si vous faites très attention, quand vous écrirez des programmes importants vous vous retrouverez certainement avec une "boucle infinie"...
Cela peut provenir de plusieurs facteurs, mais les conséquences sont les mêmes... Votre programme tournera en rond sans que vous ne puissiez le terminer normalement (comme vous l'aviez prévu).
| Astuce |
Si un de vos programmes est bloqué ou semble ne plus réagir pensez aux combinaisons de touches Ctrl + Break (arrêt défil parfois) ou Ctrl + Attn (ou encore Pause). Ctrl + C permet aussi d'arrêter le programme, mais seulement lorsqu'il est sur une procédure d'Entrée / Sortie.Il est inutile de se jeter sur les trois touches préférées de Bill Gates, gardez-les en dernier recours ;o) |
Pourtant, il peut arriver dans certaines situations que vous ayez besoin de créer une boucle infinie dans vos programmes. Ceci pour introduire un point d'échapement en plein milieu des instructions qui la composent par exemple.
Je ne conseille pas ce genre de procédé qui nuit gravement à la lisibilité du code source...
Pourtant dans certains cas il est impossible de s'en passer. Pensez donc aux procédures break et continue, consultez l'aide de votre compilateur ou posez vos questions sur notre forum si vous ne comprenez pas...

