• 20 hours
  • Easy

Free online content available in this course.

Paperback available in this course

course.header.alt.is_certifying

You can get support and mentoring from a private teacher via videoconference on this course.

Got it!

Last updated on 11/28/19

Les boucles

Log in or subscribe for free to enjoy all this course has to offer!

Nous les avons évoquées rapidement un peu plus tôt en parlant des tableaux et des listes. Dans ce chapitre nous allons décrire plus précisément les boucles.

Elles sont souvent utilisées pour parcourir des éléments énumérables, comme le sont les tableaux ou les listes. Elles peuvent également être utilisées pour effectuer la même action tant qu'une condition n'est pas réalisée.

La boucle For

La première instruction que nous avons aperçue est la boucle for. Elle permet de répéter un bout de code tant qu’une condition est vraie. Souvent cette condition est un compteur. Nous pouvons par exemple afficher un message 50 fois avec le code suivant :

int compteur;
for (compteur = 0; compteur < 50; compteur++)
{
    Console.WriteLine("Bonjour C#");
}

Ce qui donne :

Image utilisateur

Nous définissons ici un entier « compteur ». Il est initialisé à 0 en début de boucle (compteur = 0). Après chaque exécution du bloc de code du for, c’est-à-dire à chaque itération, il va afficher « Bonjour C# ».
À la fin de chaque itération, la variable compteur est incrémentée (compteur++) et nous recommençons l’opération tant que la condition « compteur < 50 » est vraie.

Bien sûr, la variable compteur est accessible dans la boucle et change de valeur à chaque itération.

int compteur;
for (compteur = 0; compteur < 50; compteur++)
{
    Console.WriteLine("Bonjour C# " + compteur);
}

Ce qui donne :

Image utilisateur

Ce précédent code affichera la valeur de la variable après chaque bonjour, donc de 0 à 49. En effet, quand compteur passe à 50, la condition n’est plus vraie et on passe aux instructions suivantes.

En général, on utilise la boucle for pour parcourir un tableau. Ainsi, nous pourrons utiliser le compteur comme indice pour accéder aux éléments du tableau :

string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
int indice;
for (indice = 0; indice < 7; indice++)
{
    Console.WriteLine(jours[indice]);
}

Dans cette boucle, comme à la première itération indice vaut 0, nous afficherons l’élément du tableau à la position 0, à savoir « Lundi ».
À l’itération suivante, indice passe à 1, nous affichons l’élément du tableau à la position 1, à savoir « Mardi », et ainsi de suite.

Ce qui donne :

Image utilisateur

Attention à ce que l’indice ne dépasse pas la taille du tableau, sinon l’accès à un indice en dehors des limites du tableau provoquera une erreur à l’exécution. Pour éviter ceci, on utilise en général la taille du tableau comme condition de fin :

string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
int indice;
for (indice = 0; indice < jours.Length; indice++)
{
    Console.WriteLine(jours[indice]);
}

Ici jours.Length renvoie la taille du tableau, à savoir 7.

Il est très courant de boucler sur un tableau en passant tous les éléments un par un, mais il est possible de changer les conditions de départ, les conditions de fin, et l’élément qui influe sur la condition de fin.

Ainsi, l’exemple suivant :

int[] chiffres = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

for (int i = 9; i > 0; i -= 2)
{
    Console.WriteLine(chiffres[i]);
}

Permet de parcourir le tableau de 2 en 2 en commençant par la fin.

Ce qui nous donne :

Image utilisateur

Vous avez pu voir que dans cet exemple, nous avons défini l’entier i directement dans l’instruction for, c’est une commodité qui nous permet d’avoir la variable i qui n’existe qu’à l’intérieur de la boucle, car sa portée correspond aux accolades qui délimitent le for.

Attention, il est possible de faire un peu tout et n’importe quoi dans ces boucles. Aussi il peut arriver que l’on se retrouve avec des bugs, comme des boucles infinies.

Par exemple, le code suivant :

for (int indice = 0; indice < 7; indice--)
{
    Console.WriteLine("Test" + indice);
}

est une boucle infinie. En effet, on modifie la variable indice en la décrémentant. Sauf que la condition de sortie de la boucle est valable pour un indice qui dépasse ou égale la valeur 7, ce qui n’arrivera jamais.

Si on exécute l’application avec ce code, la console va afficher à l’infini le mot « Test » avec son indice. La seule solution pour quitter le programme sera de fermer brutalement l’application.

L’autre solution est d’attendre que le programme se termine...

Mais tu viens de dire que la boucle était infinie ?

Oui c’est vrai, mais en fait, ici on se heurte à un cas limite du C#. C’est à cause de la variable indice. indice est un entier que l’on décrémente. Au début il vaut zéro, puis -1, puis -2, etc …
Lorsque la variable indice arrive à la limite inférieure que le type int est capable de gérer, c’est-à-dire -2147483648 alors il y a ce qu’on appelle un dépassement de capacité. Sans rentrer dans les détails, il ne peut pas stocker un entier plus petit et donc il boucle et repart à l’entier le plus grand, c’est-à-dire 2147483647.

Donc pour résumer, l’indice fait :

  • 0

  • -1

  • -2

  • ...

  • -2147483647

  • -2147483648

  • +2147483647

Et comme là, il se retrouve supérieur à 7, la boucle se termine.

Image utilisateur

Donc, techniquement, ce n’est pas une boucle infinie, mais bon, on a attendu tellement longtemps pour atteindre ce cas limite que c’est tout comme.

Et surtout, nous tombons sur un cas imprévu. Ici, ça se termine « plutôt bien », mais ça aurait pu finir en crash de l’application.

La boucle Foreach

Comme il est très courant d’utiliser les boucles pour parcourir un tableau ou une liste, le C# dispose d’un opérateur particulier : foreach que l’on peut traduire par « pour chaque » : pour chaque élément du tableau faire …

string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
foreach (string jour in jours)
{
    Console.WriteLine(jour);
}

Cette boucle va nous permettre de parcourir tous les éléments du tableau « jours ». À chaque itération, la boucle va créer une chaine de caractères « jour » qui contiendra l’élément courant du tableau. À noter que la variable « jour » aura une portée égale au bloc foreach. Nous pourrons ainsi utiliser cette valeur dans le corps de la boucle et pourquoi pas l’afficher comme dans l’exemple précédent.

Ce qui produira :

Image utilisateur

L’instruction foreach fonctionne aussi avec les listes, par exemple le code suivant :

List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
foreach (string jour in jours)
{
    Console.WriteLine(jour);
}

nous permettra d’afficher tous les jours de la semaine contenus dans la liste des jours.

Attention, la boucle foreach est une boucle en lecture seule. Cela veut dire qu'il n'est pas possible de modifier l'élément de l'itération en cours.

Par exemple, le code suivant :

List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
foreach (string jour in jours)
{
    jour = "pas de jour !";
}

provoquera l'erreur de compilation suivante :

Citation : Compilateur

Impossible d'assigner à 'jour', car il s'agit d'un 'variable d'itération foreach'

Notez d'ailleurs que l'équipe de traduction de Visual Studio Express a quelques progrès à faire :D ...

Si nous souhaitons utiliser une boucle pour changer la valeur de notre liste ou de notre tableau, il faudra passer par une boucle for :

List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
for (int i = 0; i < jours.Count; i++ )
{
    jours[i] = "pas de jour !";
}

Il vous arrivera aussi surement un jour (ça arrive à tous les développeurs) de vouloir modifier une liste en elle même lors d'une boucle foreach. C'est-à-dire lui rajouter un élément, le supprimer, etc ...
C'est également impossible car à partir du moment où l'on rentre dans la boucle foreach, la liste devient non-modifiable.

Prenons l'exemple ô combien classique de la recherche d'une valeur dans une liste pour la supprimer. Nous serions tenté de faire :

List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
foreach (string jour in jours)
{
    if (jour == "Mercredi")
        jours.Remove(jour);
}

ce qui semblerait tout à fait correct et en plus, ne provoque pas d'erreur de compilation.

Sauf que si vous exécutez l'application, vous aurez l'erreur suivante :

Image utilisateur

qui nous plante notre application. Le programme nous indique que « la collection a été modifiée » et que « l'opération d'énumération peut ne pas s'exécuter ».

Il est donc impossible de faire notre suppression ainsi.

Comment tu ferais toi ?

Et bien, plusieurs solutions existent. Celle qui vient en premier à l'esprit est d'utiliser une boucle for par exemple :

for (int i = 0 ; i < jours.Count ; i++)
{
    if (jours[i]== "Mercredi")
        jours.Remove(jours[i]);
}

Cette solution est intéressante ici, mais elle peut poser un problème dans d'autres situations. En effet, vu que nous supprimons un élément de la liste, nous allons nous retrouver avec une incohérence entre l'indice en cours et l'élément que nous essayons d'atteindre. En effet, lorsque le jour courant est Mercredi, l'indice i vaut 2. Si l'on supprime cet élément, c'est Jeudi qui va se retrouver en position 2. Et nous allons rater son analyse car la boucle va continuer à l'indice 3, qui sera Vendredi.
On peut éviter ce problème en parcourant la boucle à l'envers :

for (int i = jours.Count - 1; i >= 0; i--)
{
    if (jours[i] == "Mercredi")
        jours.Remove(jours[i]);
}

Nous n'étudierons pas les autres solutions car elles font appels à des notions que nous verrons en détail dans un prochain cours.

Après avoir lu ceci, vous pourriez avoir l'impression que la boucle foreach n'est pas souple et difficilement exploitable, autant utiliser autre chose ...
Vous verrez à l'utilisation que non, elle est en fait très pratique. Il faut simplement connaître ses limites. Voilà qui est chose faite. ^^

Nous avons vu que l’instruction foreach permettait de boucler sur tous les éléments d’un tableau ou d’une liste. En fait, il est possible de parcourir tous les types qui sont énumérables.
Nous verrons dans le prochain cours ce qui caractérise un type énumérable, car pour l’instant, c’est un secret ! Chuuut ;) .

La boucle While

La boucle while est en général moins utilisée que for ou foreach. C’est la boucle qui va nous permettre de faire quelque chose tant qu’une condition n’est pas vérifiée. Elle ressemble de loin à la boucle for, mais la boucle for se spécialise dans le parcours de tableau tandis que la boucle while est plus générique.

Par exemple :

int i = 0;
while (i < 50)
{
    Console.WriteLine("Bonjour C#");
    i++;
}

Permet d’écrire « Bonjour C# » 50 fois de suite.
Ici, la condition du while est évaluée en début de boucle.

Dans l’exemple suivant :

int i = 0;
do
{
    Console.WriteLine("Bonjour C#");
    i++;
}
while (i < 50);

La condition de sortie de boucle est évaluée à la fin de la boucle. L’utilisation du mot clé do permet d’indiquer le début de la boucle.

Concrètement cela veut dire que dans le premier exemple, le code à l’intérieur de la boucle peut ne jamais être exécuté, si par exemple l’entier i est initialisé à 50. A contrario, on passera au moins une fois dans le corps de la boucle du second exemple, même si l’entier i est initialisé à 50 car la condition de sortie de boucle est évaluée à la fin.

Les conditions de sorties de boucles ne portent pas forcément sur un compteur ou un indice, n’importe quelle expression peut être évaluée. Par exemple :

string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
int i = 0;
bool trouve = false;
while (!trouve)
{
    string valeur = jours[i];
    if (valeur == "Jeudi")
    {
        trouve = true;
    }
    else
    {
        i++;
    }
}
Console.WriteLine("Trouvé à l'indice " + i);

Le code précédant va répéter les instructions contenues dans la boucle while tant que le booléen « trouve » sera faux (c'est-à-dire qu’on va s’arrêter dès que le booléen sera vrai). Nous analysons la valeur à l’indice i, si la valeur est celle cherchée, alors nous passons le booléen à vrai et nous pourrons sortir de la boucle. Sinon, nous incrémentons l’indice pour passer au suivant.

Attention encore aux valeurs de sorties de la boucle. Si nous ne trouvons pas la chaine recherchée, alors i continuera à s’incrémenter ; le booléen ne passera jamais à vrai, nous resterons bloqué dans la boucle et nous risquons d’atteindre un indice qui n’existe pas dans le tableau.
Il serait plus prudent que la condition porte également sur la taille du tableau, par exemple :

string[] jours = new string[] { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
int i = 0;
bool trouve = false;
while (i < jours.Length && !trouve)
{
    string valeur = jours[i];
    if (valeur == "Jeudi")
    {
        trouve = true;
    }
    else
    {
        i++;
    }
}
if (!trouve)
    Console.WriteLine("Valeur non trouvée");
else
    Console.WriteLine("Trouvé à l'indice " + i);

Ainsi, si l’indice est supérieur à la taille du tableau, nous sortons de la boucle et nous éliminons le risque de boucle infinie.

Une erreur classique est que la condition ne devienne jamais vraie à cause d’une erreur de programmation. Par exemple, si j’oublie d’incrémenter la variable i, alors à chaque passage de la boucle j’analyserai toujours la première valeur du tableau et je n’atteindrai jamais la taille maximale du tableau, condition qui me permettrait de sortir de la boucle.

Les instructions break et continue

Il est possible de sortir prématurément d’une boucle grâce à l’instruction break. Dès qu’elle est rencontrée, elle sort du bloc de code de la boucle. L’exécution du programme continue alors avec les instructions situées après la boucle. Par exemple :

int i = 0;
while (true)
{
    if (i >= 50)
    {
        break;
    }
    Console.WriteLine("Bonjour C#");
    i++;
}

Le code précédent pourrait potentiellement produire une boucle infinie. En effet, la condition de sortie du while est toujours vraie. Mais l’utilisation du mot clé break nous permettra de sortir de la boucle dès que i atteindra la valeur 50.
Certes ici, il suffirait que la condition de sortie porte sur l’évaluation de l’entier i. Mais il peut arriver des cas où il pourra être judicieux d’utiliser un break (surtout lors d'un déménagement !).

C’est le cas pour l’exemple suivant. Imaginons que nous voulions vérifier la présence d’une valeur dans une liste. Pour la trouver, on peut parcourir les éléments de la liste et une fois trouvée, on peut s’arrêter. En effet, il sera inutile de continuer à parcourir le reste des éléments :

List<string> jours = new List<string> { "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" };
bool trouve = false;
foreach (string jour in jours)
{
    if (jour == "Jeudi")
    {
        trouve = true;
        break;
    }
}

Nous nous économisons ici d’analyser les 3 derniers éléments de la liste.

Il est également possible de passer à l’itération suivante d’une boucle grâce à l’utilisation du mot-clé continue. Prenons l’exemple suivant :

for (int i = 0; i < 20; i++)
{
    if (i % 2 == 0)
    {
        continue;
    }
    Console.WriteLine(i);
}

Ici, l’opérateur % est appelé « modulo ». Il permet d’obtenir le reste de la division. L’opération i % 2 renverra donc 0 quand i sera pair. Ainsi, dès qu’un nombre pair est trouvé, nous passons à l’itération suivante grâce au mot clé continue. Ce qui fait que nous n'allons afficher que les nombres impairs.

Ce qui donne :

Image utilisateur

Bien sûr, il aurait été possible d’inverser la condition du if pour ne faire le Console.WriteLine() que dans le cas où i % 2 != 0. À vous de choisir l’écriture que vous préférez en fonction des cas que vous rencontrerez.

En résumé
  • On utilise la boucle for pour répéter des instructions tant qu'une condition n'est pas vérifiée, les éléments de la condition changeant à chaque itération.

  • On utilise en général la boucle for pour parcourir un tableau, avec un indice qui s'incrémente à chaque itération.

  • La boucle foreach est utilisée pour simplifier le parcours des tableaux ou des listes.

  • La boucle while permet de répéter des instructions tant qu'une condition n'est pas vérifiée. C'est la boucle la plus souple.

  • Il faut faire attention aux conditions de sortie d'une boucle afin d'éviter les boucles infinies qui font planter l'application.

Example of certificate of achievement
Example of certificate of achievement