Licence CC 0

Les boucles

Dernière mise à jour :

Dans ce chapitre, nous allons aborder les boucles. Une boucle est un moyen de répéter des instructions suivant le résultat d’une condition. Ces structures, dîtes itératives, que nous allons voir dans ce chapitre sont les suivantes.

Structure itérative Action
while… répète une suite d’instructions tant qu’une condition est respectée.
do… while… répète une suite d’instructions tant qu’une condition est respectée. Le groupe d’instructions est exécuté au moins une fois.
for… répète un nombre fixé de fois une suite d’instructions.

La boucle while

La première des boucles que nous allons étudier est la boucle while (qui signifie « tant que »). Celle-ci permet de répéter un bloc d’instructions tant qu’une condition est remplie.

Structure While

Syntaxe

La syntaxe de notre boucle while est assez simple.

1
2
3
4
while (/* Condition */)
{
    /* Bloc d'instructions à répéter */ 
}

Exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <stdio.h>


int main(void)
{
    int i = 0;

    while (i < 5)
    {
        printf("La variable i vaut %d\n", i);
        i++;
    }

    return 0;
}
1
2
3
4
5
La variable i vaut 0
La variable i vaut 1
La variable i vaut 2
La variable i vaut 3
La variable i vaut 4

Le fonctionnement est simple à comprendre :

  • Au départ, notre variable i vaut zéro. Étant donné que zéro est bien inférieur à cinq, la condition est vraie, le corps de la boucle est donc exécuté.
  • La valeur de i est affichée.
  • i est augmentée d’une unité et vaut désormais un.
  • La condition de la boucle est de nouveau vérifiée.

Ces étapes vont ainsi se répéter pour les valeurs un, deux, trois et quatre. Quand la variable i vaudra cinq, la condition sera fausse, et l’instruction while sera alors passée.

Dans cet exemple, nous utilisons une variable nommée i. Ce nom lui vient d’une contraction du mot anglais iterator qui signifie que cette variable sert à l’itération (la répétition) du corps de la boucle. Ce nom est tellement court et explicite qu’il est pour ainsi dire devenu une convention de nommage en C.

Exercice

Essayez de réaliser un programme qui détermine si un nombre entré par l’utilisateur est premier. Pour rappel, un nombre est dit premier s’il n’est divisible que par un et par lui-même. Notez que si un nombre $x$ est divisible par $y$ alors le résultat de l’opération x % y est nul.

Indice

Pour savoir si un nombre est premier, il va vous falloir vérifier si celui-ci est uniquement divisible par un et lui-même. Dit autrement, vous allez devoir contrôler qu’aucun nombre compris entre 1 et le nombre entré (tout deux exclus) n’est un diviseur de ce dernier. Pour parcourir ces différentes possibilités, une boucle va vous être nécessaire.

Correction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>


int main(void)
{
   int nombre;
   int i = 2;

   printf("Entrez un nombre : ");
   scanf("%d", &nombre);

   while ((i < nombre) && (nombre % i != 0))
   {
       ++i;
   }

   if (i == nombre)
   {
       printf("%d est un nombre premier\n", nombre);
   }
   else
   {
       printf("%d n'est pas un nombre premier\n", nombre);
   }

   return 0;
}

La boucle do-while

La boucle do while fonctionne comme la boucle while, à un petit détail près : elle s’exécutera toujours au moins une fois, alors qu’une boucle while peut ne pas s’exécuter si la condition est fausse dès le départ.

Instruction do… while…

Syntaxe

À la différence de la boucle while, la condition est placée à la fin du bloc d’instruction à répéter, ce qui explique pourquoi celui-ci est toujours exécuté au moins une fois. Remarquez également la présence d’un point-virgule à la fin de l’instruction qui est obligatoire.

1
2
3
4
do
{
    /* Bloc d'instructions à répéter */
} while (/* Condition */);

Exemple 1

Voici le même code que celui présenté avec l’instruction while.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <stdio.h>


int main(void)
{
    int i = 0;

    do
    {
        printf("La variable i vaut %d\n", i);
        ++i;
    } while (i < 5);

    return 0;
}
1
2
3
4
5
La variable i vaut 0
La variable i vaut 1
La variable i vaut 2
La variable i vaut 3
La variable i vaut 4

Exemple 2

Comme nous vous l’avons dit plus haut, une boucle do while s’éxecute au moins une fois.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <stdio.h>


int main(void)
{    
    do
        printf("Boucle do-while\n");
    while (0);

    return 0;
}
1
Boucle do-while

Comme vous le voyez, malgré que la condition est fausse (pour rappel, une valeur nulle correspond à une valeur fausse), le corps de la boucle est exécuté une fois puisque la condition n’est évaluée qu’après que le bloc d’instructions ait été parcouru.

La boucle for

Syntaxe

1
2
3
4
for (/* Expression 1 */ ; /* Condition */ ; /* Expression 2 */)
{
    /* Instructions à répéter */
}

Une boucle for se décompose en trois parties :

  • une expression, qui sera le plus souvent l’initialisation d’une variable ;
  • une condition ;
  • une seconde expression, qui consistera le plus souvent en l’incrémentation d’une variable.

Techniquement, une boucle for revient en fait à écrire ceci.

1
2
3
4
5
6
7
/* Expression 1 */

while (/* Condition */)
{
    /* Bloc d'instructions à répéter */
    /* Expression 2 */
}

Exemple

Le fonctionnement de cette boucle est plus simple à appréhender à l’aide d’un exemple.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <stdio.h>


int main(void)
{
    int i;

    for (i = 0 ; i < 5 ; ++i)
        printf("la variable i vaut %d\n", i);

    return 0;
}
1
2
3
4
5
variable vaut 0
variable vaut 1
variable vaut 2
variable vaut 3
variable vaut 4

Ce qui, comme dit précédemment, revient exactement à écrire cela.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <stdio.h>


int main(void)
{
    int i;

    i = 0;

    while (i < 5)
    {
        printf("la variable i vaut %d\n", i);
        ++i;
    }

    return 0;
}

Notez bien que la première expression, i = 0, est située en dehors du corps de la boucle. Elle n’est donc pas évaluée à chaque tour.

Exercice

Essayez de réaliser un programme qui calcule la somme de tous les nombres compris entre un et $n$ ($n$ étant déterminé par vos soins). Autrement dit, pour un nombre $n$ donné, vous allez devoir calculer $1 + 2 + 3 + ... + (n-2) + (n-1) + n$.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <stdio.h>


int main (void)
{
    const unsigned int n = 250;
    unsigned int somme = 0;
    unsigned int i;

    for (i = 1; i <= n; ++i)
        somme += i;

    printf ("Somme de 1 à %u : %u\n", n, somme);
    return 0;
}

Notez qu’il est possible de réaliser cet exercice sans boucle en calculant : $\frac {N \times (N+1)} {2}$.

Plusieurs compteurs

Notez que le nombre de compteurs ou de conditions n’est pas limité, comme le démontre le code suivant.

1
for (i = 0, j = 2 ; i < 10 && j < 12; i++, j += 2)

Ici, nous définissons deux compteurs i et j initialisés respectivement à zéro et deux. Le contenu de la boucle est exécuté tant que i est inférieur à dix et que j est inférieur à douze, i étant augmentée de une unité et j de deux unités à chaque tour de boucle. Le code est encore assez lisible, cependant la modération est de mise, un trop grand nombre de paramètres rendant la boucle for illisible.

Imbrications

Il est parfaitement possible d’imbriquer une ou plusieurs boucles en plaçant une boucle dans le corps d’une autre boucle.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int i;
int j;

for (i = 0 ; i < 1000 ; ++i)
{
    for (j = i ; j < 1000 ; ++j)
    {
          /*  Code  */
    }
}

Cela peut servir par exemple pour déterminer la liste des nombres dont le produit vaut mille.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <stdio.h>


int main(void)
{
    int i;
    int j;

    for (i = 0 ; i <= 1000 ; ++i)
    {
        for (j = i ; j <= 1000 ; ++j)
            if (i * j == 1000) 
                printf ("%d * %d = 1000 \n", i, j);
    }

    return 0;
}
1
2
3
4
5
6
7
8
1 * 1000 = 1000 
2 * 500 = 1000 
4 * 250 = 1000 
5 * 200 = 1000 
8 * 125 = 1000 
10 * 100 = 1000 
20 * 50 = 1000 
25 * 40 = 1000 

Vous n’êtes bien entendu pas tenu d’imbriquer des types de boucles identiques. Vous pouvez parfaitement plaçer, par exemple, une boucle while dans une boucle for.

Boucles infinies

Lorsque vous utilisez une boucle, il y a une chose que vous devez impérativement vérifier : elle doit pouvoir se terminer. Cela paraît évident de prime abord, pourtant il s’agit d’une erreur de programmation assez fréquente qui donne lieu à des boucles infinies. Soyez donc vigilants !

L’exemple le plus fréquent est l’oubli d’incrémentation de l’itérateur.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <stdio.h>

int main(void)
{
    int i = 0;

    while (i < 5)
    {
        printf("La variable i vaut %d\n", i);
        /* Oubli d'incrémentation */
    }

    return 0;
}
1
2
3
4
La variable i vaut 0
La variable i vaut 0
La variable i vaut 0
...

Ce code continuera jusqu’à ce que l’utilisateur arrête le programme.

Exercices

Calcul du PGCD de deux nombres

Le PGCD de deux nombres est le plus grand nombre qui peut diviser ces derniers. Par exemple, le PGCD de quinze et douze est trois et celui de vingt-quatre et dix-huit est six.

Pour le calculer, nous devons disposer de deux nombres $a$ et $b$ avec $a$ supérieur à $b$. Ensuite, nous effectuons la division entière de $a$ par $b$.

  • si le reste est nul, alors nous avons terminé ;
  • si le reste est non nul, nous revenons au début en remplaçant $a$ par $b$ et $b$ par le reste.

Avec cette explication, vous avez tout ce qu’il vous faut : à vos claviers !

Correction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>


int main (void)
{
    unsigned int a = 46;
    unsigned int b = 42;
    unsigned int reste = a % b;

    while (reste != 0)
    {
        a = b;
        b = reste;
        reste = a % b;
    }

    printf("%d", b);
    return 0;
}

Une overdose de lapins

Au treizième siècle, un mathématicien italien du nom de Leonardo Fibonacci posa un petit problème dans un de ses livres, qui mettait en scène des lapins. Ce petit problème mis en avant une suite de nombres particulière, nommée la suite de Fibonnaci, du nom de son inventeur. Il fit les hypothèses suivantes :

  • le premier mois, nous plaçons un couple de deux lapins dans un enclos ;
  • un couple de lapin ne peut procréer qu’à partir du troisième mois de sa venue dans l’enclos (autrement dit, il ne se passe rien pendant les deux premiers mois) ;
  • chaque couple capable de procréer donne naissance à un nouveau couple ;
  • enfin, pour éviter tout problème avec la SPA, les lapins ne meurent jamais.

Le problème est le suivant : combien y a-t-il de couples de lapins dans l’enclos au n-ième mois ? Le but de cet exercice est de réaliser un petit programme qui fasse ce calcul automatiquement.

Indice

Allez, un petit coup de pouce : suivant l’énoncé, un couple ne donne naissance à un autre couple qu’au début du troisième mois de son apparition. Combien de couple y a-t-il le premier mois ? Un seul. Combien y en a-t-il le deuxième mois ? Toujours un seul. Combien y en a-t-il le troisième mois (le premier couple étant là depuis deux mois) ? Deux. Avec ceci, vous devriez venir à bout du problème.

Correction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>


int main(void)
{
   int a;
   int b;
   int nb_lapins = 1;
   int const mois = 10;
   int i;

   a = 0;
   b = 1;

   for (i = 1; i < mois; ++i)
   {
       nb_lapins = a + b;
       a = b;
       b = nb_lapins;
   }

   printf("Au mois %d, il y a %d lapins\n", mois, nb_lapins);
   return 0;  
}

Des pieds et des mains pour convertir mille miles

Si vous avez déjà voyagé en Grande-Bretagne ou aux États-unis, vous savez que les unités de mesure utilisées dans ces pays sont différentes des nôtres. Au lieu de notre cher système métrique, dont les stars sont les centimètres, mètres et kilomètres, nos amis outre-manche et outre-atlantique utilisent le système impérial, avec ses pouces, pieds et miles, voire lieues et furlongs ! Et pour empirer les choses, la conversion n’est pas toujours simple à effectuer de tête… Aussi, la lecture d’un ouvrage tel que Le Seigneur des Anneaux, dans lequel toutes les distances sont exprimées en unités impériales, peut se révéler pénible.

Grâce au langage C, nous allons aujourd’hui résoudre tous ces problèmes ! Votre mission, si vous l’acceptez, sera d’écrire un programme affichant un tableau de conversion entre miles et kilomètres. Le programme ne demande rien à l’utilisateur, mais doit afficher quelque chose comme ceci.

1
2
3
4
5
6
7
Miles    Km
5        8
10       16
15       24
20       32
25       40
30       48

Autrement dit, le programme compte les kilomètres de cinq en cinq jusqu’à trente et affiche à chaque fois la valeur correspondante en miles. Un mile vaut exactement 1.609344 km, cependant nous allons utiliser une valeur approchée : huit-cinquièmes de kilomètre (soit 1.6km). Autrement dit, $1$ miles $= \frac{8}{5}$ km ou ($1$ km $= \frac{5}{8}$ miles).

Correction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#include <stdio.h>


int main(void)
{
    unsigned miles = 0;

    printf("Miles\tKm\n");

    do
    {
        ++miles;
        printf("%u\t%u\n", miles * 5, miles * 8);
    } while (miles * 5 < 30);
    
    return 0;
}

Puissances de trois

Passons à un exercice un peu plus difficile, du domaine des mathématiques. Essayez de le faire même si vous n’aimez pas les mathématiques.

Vous devez vérifier si un nombre est une puissance de trois, et afficher le résultat. De plus, si c’est le cas, vous devez afficher l’exposant qui va avec.

Indice

Pour savoir si un nombre est une puissance de trois, vous pouvez utiliser le modulo. Attention cependant : si le reste vaut 0, le nombre n’est pas forcément une puissance de trois (par exemple, le reste de la division de 15 par 3 est nul, mais 15 n’est pas une puissance de trois).

Correction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>


/* Un petite explication s'impose, notamment au niveau du for. La première
partie qui correspond à l'initialisation de i ne devrait pas vous poser
trop de soucis. Ensuite, le i /= 3 sert à diviser i par trois à chaque
itération. Au tour de la condition, le principe est simple : tant que le
reste de la division de i par 3 est égal à zéro et que i est positif, on
incrémente l'exposant. Enfin, pour déterminer si le nombre est une puissance
de trois, il suffit de vérifier si i est égal à 1 (essayez avec de petits
nombres dans votre tête ou sur papier si vous n'êtes pas convaincu). */ 

int main(void)
{
    int number, i;
    int exposant = 0;

    printf("Veuillez entrez un nombre : ");
    scanf("%d", &number);

    for (i = number; (i % 3 == 0) && (i > 0); i /= 3)
    {
        ++exposant;
    }

    /* Chaque division successive divise i par 3, donc si nous obtenons finalement
    i == 1, c'est que le nombre est bien une puissance de 3 */

    if (i == 1)
    {
        printf ("%d est égal à 3 ^ %d\n", number, exposant);
    }
    else
    {
        printf("%d n'est pas une puissance de 3\n", number);
    }

    return 0;
}

La disparition : le retour

Connaissez-vous le roman La Disparition ? Il s’agit d’un roman français de Georges Perec, publié en 1969. Sa particularité est qu’il ne contient pas une seule fois la lettre « e ». On appelle ce genre de textes privés d’une lettre des lipogrammes. Celui-ci est une prouesse littéraire, car la lettre « e » est la plus fréquente de la langue française : elle représente une lettre sur six en moyenne ! Le roman faisant environ trois cents pages, il a sûrement fallu déployer des trésors d’inventivité pour éviter tous les mots contenant un « e ».

Si vous essayez de composer un tel texte, vous allez vite vous rendre compte que vous glissez souvent des « e » dans vos phrases sans même vous en apercevoir. Nous avons besoin d’un vérificateur qui nous sermonnera chaque fois que nous écrirons un « e ». C’est là que le langage C entre en scène !

Écrivez un programme qui demande à l’utilisateur de taper une phrase, puis qui affiche le nombre de « e » qu’il y a dans celle-ci. Une phrase se termine toujours par un point « . », un point d’exclamation « ! » ou un point d’interrogation « ? ». Pour effectuer cet exercice, il sera indispensable de lire la phrase caractère par caractère.

1
2
Entrez une phrase : Bonjour, comment allez-vous ?
Au moins une lettre 'e' a été repérée (précisémment : 2) !

Indice

La première chose à faire est d’afficher un message de bienvenue, afin que l’utilisateur sache quel est votre programme. Ensuite, Il vous faudra lire les caractères tapés (rappelez-vous les différents formats de la fonction scanf()), un par un, jusqu’à ce qu’un point (normal, d’exclamation ou d’interrogation) soit rencontré. Dans l’intervalle, il faudra compter chaque « e » qui apparaîtra. Enfin, il faudra afficher le nombre de « e » qui ont été comptés (potentiellement aucun).

Correction

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>

int main(void)
{
    unsigned compteur = 0;
    char c;

    printf("Entrez une phrase se terminant par '.', '!' ou '?' : ");

    do
    {
        scanf("%c", &c);
        if (c == 'e' || c == 'E')
        {
            compteur++;
        }
    } while (c != '.' && c != '!' && c != '?');
    
    if (compteur == 0)
    {
        printf("Aucune lettre 'e' repérée. Félicitations !\n");
    }
    else
    {
        printf("Au moins une lettre 'e' a été repérée (précisémment : %d) !\n", compteur);
    }
    
    return 0;
}

Les boucles sont assez faciles à comprendre, la seule chose dont il faut se souvenir étant de faire attention de bien avoir une condition de sortie pour ne pas tomber dans une boucle infinie. Le prochain chapitre abordera la notion de saut.