serhane le crackeur
  1.5 Répétitions
 

1.5 Répétitions

1.5.1 Répéter un bloc

L'un des avantages des ordinateurs est qu'ils sont capables d'effectuer des opérations un très grand nombre de fois, rapidement et sans fatiguer. Pour en profiter, il nous faut une structure permettant de répéter un morceau de programme plusieurs fois. Nous allons voir une première méthode pour le faire, la boucle while :

while (...condition du while...)
   (...bloc du while)

On remarque tout de suite que la structure while (qui signifie "tant que" en anglais) est similaire à celle du if. Son principe d'exécution a également des points communs, mais comporte une différence importante.

Fonctionnement d'une boucle while, utilisée pour répéter l'exécution d'un bloc :

La condition d'un while prend exactement la même forme que celle d'un if. Il en est de même pour le bloc. Voyons tout de suite un exemple : écrivons un programme qui demande à un utilisateur d'entrer un code secret (un entier). Si le code secret n'est pas celui attendu par le programme (456), le programme le lui redemande à nouveau, et répète l'opération jusqu'à-ce que le bon code soit entré par l'utilisateur.

On peut écrire le pseudo-code de notre idée. Le pseudo-code a pour but de décrire chaque étape en français, comme dans un programme, avant d'écrire le programme lui-même. On peut ainsi réfléchir à son principe, avant de se préoccuper des détails de l'écriture du programme.

Créer une variable qui contiendra le code entré par l'utilisateur.
Au départ, l'initialiser à 0.
Tant que le code entré par l'utilisateur n'est pas le code recherché (456) :
   - Demander à l'utilisateur de taper son code secret
   - stocker l'entier tapé par l'utilisateur dans notre variable
   - recommencer la boucle
Afficher un message indiquant que le code secret a été trouvé.

Voyons maintenant comment traduire ce programme en langage C :


#include <stdio.h>

int main()
{
   int code = 0;
   while (code != 456)
   {
      printf("Entrez le code secret numériquen");
      scanf("%d", &code);
   }
   printf("Bravo, vous avez trouvé le code secretn");
   return 0;
}

Ce programme demande à l'utilisateur d'entrer un code secret numérique et recommence inlassablement, tant que l'utilisateur n'entre pas le bon code secret : 456. Etudions d'un peu plus près son déroulement :

  • La variable code est déclarée et initialisée à la valeur 0.
  • La condition code != 456 est testée et est vraie, car 0 est différent de 456.
  • Le bloc du while est donc exécuté, en commençant par l'affichage du message demandant le code secret.
  • Le scanf attend ensuite l'entrée d'un entier, qui est stocké dans la variable code. Supposons que l'utilisateur tape 42.
  • La condition du while est de nouveau testée et est de nouveau vraie, car 42 est différent de 456.
  • Le bloc du while est de nouveau exécuté et un nouveau code secret est lu. Supposons cette fois que l'utilisateur tape 456.
  • La condition est testée une fois de plus, mais est cette fois fausse, puisque 456 n'est pas différent de lui-même.
  • Le bloc du while n'est pas exécuté et l'exécution se poursuit après la fin de celui-ci.
  • Le message de félicitations est alors affiché, et le programme se termine.

Comme dans le cas du if, on peut d'ailleurs simplifier l'écriture du bloc, s'il ne contient qu'une seule instruction. Par exemple si l'on ne souhaite afficher le texte "Entrez le code secret numérique" que la première fois, on écrira :


#include <stdio.h>

int main()
{
   int code = 0;
   printf("Entrez le code secret numériquen");
   while (code != 456)
      scanf("%d", &code);
   printf("Bravo, vous avez trouvé le code secretn");
   return 0;
}

Dans la description du déroulement du programme, on s'est arrêté à deux exécutions de la boucle (pour trois tests de la condition), mais on aurait pu en faire beaucoup plus, si l'utilisateur n'avait pas tapé le bon code. Si l'on ne fait pas attention, on peut obtenir un programme qui ne se terminera jamais, quoi que fasse l'utilisateur, comme c'est le cas du code ci-dessous :


while (0 + 0 == 0)
   printf("La tête à toton");
printf("Terminén");

La condition 0 + 0 == 0 est toujours vraie et le programme va donc afficher "La tête à toton" un nombre infini de fois et ne s'arrêtera jamais. Comme la seule instruction du bloc ne modifie rien qui puisse changer le fait que la condition soit vraie, cette condition ne sera jamais fausse, et les instructions qui suivent le bloc du while ne seront jamais exécutées. Le texte "Terminé" n'apparaîtra donc jamais, aussi longtemps que vous attendiez.

Exercice : écrivez un programme qui demande à l'utilisateur "Entrez votre code secret : " suivi d'un retour à la ligne, puis attend un entier, et affiche "Confirmez votre code secret : " (suivi d'un retour à la ligne) et attend un deuxième entier. Le programme doit répéter ces deux questions, jusqu'à-ce que que l'utilisateur entre bien deux fois le même nombre, puis afficher "merci".

 


Solution :


#include <stdio.h>

int main()
{
   int code = 0;
   int confirmation = 1;
   while (code != confirmation)
   {
      printf("Entrez votre code secret : n");
      scanf("%d", &code);
      printf("Confirmez votre code secret : n");
      scanf("%d", &confirmation);
   }
   printf("mercin");
   return 0;
}

1.5.2 Répéter un nombre de fois donné

On a souvent besoin d'exécuter exactement la même opération un nombre bien précis de fois. On peut le faire avec une boucle while, en utilisant une variable, dans lequel on va stocker le nombre d'exécutions du bloc du while déjà effectuées. Il suffit alors de mettre comme condition du while, que le compteur doit être inférieur à une valeur donnée, pour que la boucle continue à s'exécuter.

Voyons par exemple le pseudo-code d'un programme qui affiche quatre fois "Hello World !".

initialiser le compteur à 0
tant que le compteur n'a pas atteint 4 :
 - afficher "Hello World !"
 - augmenter le compteur de 1

Vérifions que l'on affiche bien exactement quatre fois le mot "Hello World !" :

  • Le compteur vaut 0, donc on exécute la boucle.
  • On affiche "Hello World !", et on augmente le compteur de 1.
  • Le compteur vaut 1, donc on exécute le corps de la boucle.
  • On affiche "Hello World !", et on augmente le compteur de 1.
  • Le compteur vaut 2, donc on exécute le corps de la boucle.
  • On affiche "Hello World !", et on augmente le compteur de 1.
  • Le compteur vaut 3, donc on exécute le corps de la boucle.
  • On affiche "Hello World !", et on augmente le compteur de 1.
  • Le compteur vaut 4, donc on a atteint 4, on n'exécute pas le corps de la boucle.

On compte donc bien quatre affichages. Il est important de remarquer que l'on doit tester si le compteur vaut exactement 4. Si l'on testait s'il dépasse 4, on afficherait "Hello World !" une fois de trop.

Voyons maintenant comment transformer notre pseudo-code en programme C. Vous pouvez essayer par vous-même avant de lire la suite.

Pour commencer, nous devons choisir un identifiant pour notre compteur. On pourrait l'appeler simplement "compteur", mais ce n'est pas une très bonne idée, car c'est un peu vague et rendrait le programme difficile à comprendre. Mieux vaut par exemple choisir le nom plus explicite "nombreAffichages" qui permet de comprendre facilement que la variable contient le nombre de fois où le texte à été affiché. On peut choisir aussi "nbAffichages" qui est presque aussi clair, mais un peu plus court.

L'étape suivante consiste à déterminer ce que l'on met exactement comme condition. On doit exécuter le corps de la boucle si le compteur est plus petit que 4, mais pas s'il y est égal. On écrit donc (nbAffichages < 4).

Il reste à trouver comment on augmente le compteur de 1. Il suffit pour cela d'écrire nbAffichages = nbAffichages + 1.

Voici le programme C correspondant :

 


#include <stdio.h>

int main()
{
   int nbAffichages = 0;
   while (nbAffichages < 4)
   {
      printf("Hello World!n");
      nbAffichages = nbAffichages + 1;
   }
   return 0;
}

Exercice : écrivez un programme qui lit un entier au clavier et affiche le texte "bonjour" suivi d'un retour à la ligne, autant de fois que la valeur du nombre fourni par l'utilisateur.

 


Solution :


#include <stdio.h>

int main()
{
   int totalAffichages;
   int nbAffichages = 0;
   scanf("%d", &totalAffichages);
   while (nbAffichages < totalAffichages)
   {
      printf("bonjourn");
      nbAffichages = nbAffichages + 1;
   }
   return 0;
}
 nbAffichages = 0;
   while (nbAffichages < 3)
   {
      int nombre;
      scanf("%d", &nombre);
      printf("Votre nombre est %dn", nombre);
      nbAffichages = nbAffichages + 1;
   }

 


1.5.3 Règles générales sur les blocs

Comme pour le bloc du if ou du else, il est possible de déclarer des variables au début du bloc d'instructions du while, à l'intérieur des accolades. Ici aussi, les variables déclarées ne sont utilisables qu'à l'intérieur du bloc. Le même principe peut en fait s'appliquer à tout bloc d'instructions se trouvant à l'intérieur d'accolades :

Les déclarations de variables réalisées à l'intérieur du corps d'un bloc ont une portée limitée à ce bloc (entre les accolades).

De même, on peut généraliser les règles suivantes :

Un bloc d'instructions ne contenant qu'une instruction ne nécessite pas d'accolades.

Un bloc d'instructions ne contenant aucune instruction peut être remplacé par un point virgule.

Attention : vous avez sans doute remarqué que toutes nos instructions se trouvent elles-mêmes entre des accolades, entre la ligne qui suit le int main() et la dernière ligne. Les deux règles ci-dessus ne s'appliquent pas à ces accolades, comme nous le reverrons plus tard.

Il est possible de créer des blocs d'instructions à l'intérieur d'un programme, sans que ce soit dans le cadre d'un if ou d'un while, ni d'une autre structure. Il suffit pour cela de mettre plusieurs instructions entre accolades, à n'importe quel endroit où l'on aurait pu mettre une instruction.

Prenons par exemple le morceau de programme suivant :

int

On peut réécrire ce programme sans utiliser de boucle, mais en gardant les instructions du corps de la boucle dans un bloc d'instructions (ceci n'a pas d'autre intérêt que d'aider à comprendre la notion de bloc) :

{
      int nombre;
      scanf("%d", &nombre);
      printf("Votre nombre est %dn", nombre);
   }
   {
      int nombre;
      scanf("%d", &nombre);
      printf("Votre nombre est %dn", nombre);
   }
   {
      int nombre;
      scanf("%d", &nombre);
      printf("Votre nombre est %dn", nombre);
   }

Il faut bien comprendre qu'à l'intérieur de chaque bloc, une nouvelle variable est déclarée, indépendante de celles des autres blocs. La variable nombre n'existe plus dès que l'on sort d'un bloc, et n'est donc pas valide en dehors de ceux-ci. On en recrée une entièrement au début de chaque bloc.

1.5.4 Itérer un bloc

Répéter exactement la même chose ne sert en fait pas souvent. On a plutôt besoin de répéter presque la même chose, mais pour une valeur différente à chaque fois. Voyons un exemple :

printf("%dn", 5);
   printf("%dn", 6);
   printf("%dn", 7);
   printf("%dn", 8);
 nombreAffiche = 5;
   printf("%dn", nombreAffiche);
   nombreAffiche = nombreAffiche + 1;
   printf("%dn", nombreAffiche);
   nombreAffiche = nombreAffiche + 1;
   printf("%dn", nombreAffiche);
   nombreAffiche = nombreAffiche + 1;
   printf("%dn", nombreAffiche);
 nombreAffiche = 5;
   int nbAffichages = 0;
   while (nbAffichages < 4)
   {
      printf("%dn", nombreAffiche);
      nombreAffiche = nombreAffiche + 1;
      nbAffichages = nbAffichages + 1;
   }

On a quatre fois la même instruction, avec juste un nombre qui change. Il est cependant possible d'écrire le même programme en écrivant plusieurs fois exactement la même chose. Il faut pour cela utiliser une variable, qui contiendra la valeur à afficher, et que l'on augmente de 1 entre chaque affichage :

int

On a ainsi obtenu maintenant trois fois exactement les mêmes deux instructions, et une fois de plus l'une des deux. Si l'on ajoute l'instruction nombreAffiche = nombreAffiche + 1; à la fin, on peut avoir quatre fois exactement la même chose, sans changer le fonctionnement du programme.

Maintenant qu'on a quatre fois la même chose, on peut utiliser une boucle qui répète ces deux instructions quatre fois, en utilisant ce que l'on a appris plus haut :

int

On peut cependant remarquer que nos deux variables, nombreAffiche et nbAffichages sont toutes deux augmentées de 1 à chaque exécution (on dit itération) de la boucle. Il est en fait possible d'écrire la même chose avec une seule variable, en utilisant nombreAffiche comme compteur de la boucle. La condition doit cependant être transformée, car la boucle doit s'exécuter tant que le nombre affiché ne dépasse pas 8. Le programme complet est alors le suivant :


#include <stdio.h>

int main()
{
   int nombreAffiche = 5;
   while (nombreAffiche < 9)
   {
      printf("%dn", nombreAffiche);
      nombreAffiche = nombreAffiche + 1;
   }
   return 0;
}

1.5.5 Exercices

Exercice : écrivez un programme qui affiche, pour chaque entier de 1 à 20, sa valeur, un espace, le texte "au carré vaut", un espace, la valeur de son carré et un retour à la ligne :

 

1 au carré vaut 1
2 au carré vaut 4
3 au carré vaut 9
...

 


Solution :


#include <stdio.h>

int main()
{
   int nombre = 1;
   while (nombre < 21)
   {
      printf("%d au carré vaut %dn", nombre, nombre*nombre);
      nombre = nombre + 1;
   }
   return 0;
}

Exercice : écrivez un programme qui lit deux nombres au clavier et qui affiche dans l'ordre, un par ligne, tous les entiers compris entre ces deux nombres. On suppose que l'utilisateur entre le plus petit des deux nombres en premier.

Par exemple si l'utilisateur entre 211 puis 214, le programme devra afficher :

211
212
213
214

 


Solution :


#include <stdio.h>

int main()
{
   int nombreActuel;
   int nombreFin;
   scanf("%d%d", &nombreActuel, &nombreFin);
   while (nombreActuel <= nombreFin)
   {
      printf("%dn", nombreActuel);
      nombreActuel = nombreActuel + 1;
   }
   return 0;
}

Exercice : transformez votre programme de l'exercice précédent, pour que les nombres soient désormais affichés sur la même ligne, séparés par des virgules. Attention : il ne faut pas afficher de virgule après le dernier nombre, mais aller à la ligne.

Si l'utilisateur entre 42 puis 49, votre programme devra alors afficher :

42,43,44,45,46,47,48,49

Solution :

Dans cet exercice, on ne peut pas se contenter d'utiliser exactement les mêmes instructions un certain nombre de fois, puisqu'on doit afficher une virgule de moins que de nombres. Il y a deux manières de résoudre le problème :

 

  • Afficher tous les nombres et la virgule qui les suit dans une boucle, sauf le dernier nombre, que l'on affiche en dehors de la boucle. Voici ce que cela donne (on a maintenant un inférieur strict "<" dans la condition) :
    
    #include <stdio.h>
    
    int main()
    {
       int nombreActuel;
       int nombreFin;
       scanf("%d%d", &nombreActuel, &nombreFin);
       while (nombreActuel < nombreFin)
       {
          printf("%d,", nombreActuel);
          nombreActuel = nombreActuel + 1;
       }
       printf("%dn", nombreActuel);
       return 0;
    }

    Remarque : lorsque l'on exécute la dernière instruction, on vient d'échouer le test de la condition du while pour la première fois, ce qui veut dire que nombreActuel vaut nombreFin. On peut donc afficher l'une ou l'autre variable.

     

  • La deuxième solution consiste à afficher tous les nombres dans la boucle, mais à n'afficher la virgule que si l'on n'est pas rendu au dernier nombre. On affiche enfin le retour à la ligne une fois sorti de la boucle :
    
    #include <stdio.h>
    
    int main()
    {
       int nombreActuel;
       int nombreFin;
       scanf("%d%d", &nombreActuel, &nombreFin);
       while (nombreActuel <= nombreFin)
       {
          printf("%d", nombreActuel);
          if (nombreActuel != nombreFin)
             printf(",");
          nombreActuel = nombreActuel + 1;
       }
       printf("n");
       return 0;
    }

    Parmi ces deux solutions, la première peut sembler un peu plus simple et plus courte. Cependant, dans le cas où l'on doit faire plus qu'afficher un nombre et une virgule à chaque itération de la boucle, mais que le corps de celle-ci contient plusieurs instructions, la première solution nécessite de recopier chacune de ces instructions après le corps de la boucle, pour l'exécution du dernier cas.

    On préfèrera donc plutôt la deuxième solution, qui évite de recopier des instructions, ce qui est toujours une bonne chose.

     


    Exercice : écrivez un programme qui lit deux nombres au clavier et qui affiche dans l'ordre inverse, séparés par des virgules, les entiers compris entre ces deux valeurs, en en sautant un sur deux. On suppose que l'utilisateur entre le plus petit des deux nombres en premier.

    Par exemple, si l'utilisateur tape 11 puis 20, votre programme doit afficher :

    20,18,16,14,12

     


    Solution :

    #include <stdio.h>
    
    int main()
    {
       int nombreDebut;
       int nombreFin;
       int nombreActuel;
       scanf("%d%d", &nombreDebut, &nombreFin);
       nombreActuel = nombreFin;
       while (nombreActuel >= nombreDebut)
       {
          if (nombreActuel != nombreFin)
             printf(",");
          printf("%d", nombreActuel);
          nombreActuel = nombreActuel - 2;
       }
       return 0;
    }

    1.5.6 Opérateurs simplifiés

    Cette section présente un certain nombre d'opérateurs permettant d'écrire plus simplement des instructions que l'on utilise assez souvent. Aucune de ces instructions ne permet de faire de nouvelles choses, ce sont simplement des manières plus courtes d'écrire certaines opérations.

    Lors de l'écriture de boucles, on utilise souvent un compteur que l'on augmente de 1 à chaque itération de la boucle. Augmenter une variable de 1 s'appelle incrémenter cette variable. Cette opération est utilisée si fréquemment qu'une notation simplifiée existe dans le langage C :

    nombreActuel = nombreActuel + 1;

    Cette instruction peut aussi s'écrire de la manière suivante, exactement équivalente, mais plus courte :

    nombreActuel++;

    De même, on peut souvent avoir besoin de faire l'opération inverse : retirer 1 à la valeur d'une variable, ce qui s'appelle décrémenter cette variable. On peut ainsi écrire, pour retirer 1 à nombreActuel :

    nombreActuel--;

    Dans certaines boucles, on peut comme on l'a déjà vu en exercice, ajouter ou retirer une valeur à chaque itération, qui ne vaut pas forcément 1. On écrit par exemple :

    nombreActuel = nombreActuel - 2;

    On ne peut bien sûr pas définir de raccourcis pour chaque valeur possible que l'on peut retirer une variable. On peut cependant éviter d'avoir à toujours écrire deux fois le nom de la variable à laquelle on veut ajouter ou retirer une valeur. Pour retirer 2 à la variable nombreActuel, on peut ainsi écrire :

    nombreActuel -= 2;

    Le même type d'opérateurs existe pour toutes les opérations de base et d'autres que l'on verra plus tard. On peut par exemple écrire nombreActuel *= 3 pour multiplier nombreActuel par trois. On a également "+=" pour l'addition, et "/=" pour la division entière.

    1.5.7 Erreurs

    Essayez de compiler le source suivant :

    
    #include <stdio.h>
    
    int main()
    {
       int nombre = 1;
       while (nombre < 21)
       {
          printf("%d au carré vaut %dn", nombre, nombre*nombre);
          nombre = nombre + 1;
       printf("Le programme est terminé.n");
       return 0;
    }

    Le compilateur vous donnera une erreur de type :

    test.c: In function `main':
    test.c:16: parse error at end of input

    L'erreur peut se traduire en "Erreur de syntaxe à la fin de l'entrée". Cela signifie qu'une erreur de syntaxe est détectée à la fin de votre programme. Il faut comprendre par là que le compilateur trouve la fin du fichier, alors qu'il lui manque quelque-chose.

    Ce qui manque ici, c'est l'accolade fermante correspondant à la première accolade ouvrante. En effet, comme on a oublié de fermer le bloc du while par une accolade, le compilateur considère que ce bloc se termine à la première accolade fermante qu'il trouve, c'est-à-dire juste avant la fin du fichier. Le bloc du while est alors considéré comme terminé, mais pas l'ensemble du programme, puisqu'il faudrait une deuxième accolade fermante.

    Compilez et testez maintenant le programme suivant :

    
    #include <stdio.h>
    
    int main()
    {
       int nombre = 1;
       while (nombre = 1)
       {
           printf("Le nombre vaut %d. Entrez une autre valeur.n", nombre);
           scanf("%d", &nombre);
       }
       return 0;
    }

    Le programme vous demandera indéfiniment d'entrer d'autres valeurs, quel que soit le nombre que vous tapez. La raison est que la condition du while est fausse : pour tester si nombre vaut 1, il faut écrire (nombre == 1) et non (nombre = 1). Le signe "=" est en effet l'opérateur d'affectation, et la valeur 1 est donc stockée dans la variable nombre. La condition est dans ce cas toujours considérée comme vraie. Il faut donc bien faire attention à ne pas confondre "==" avec "=".

  •  

    • On évalue la condition.
    • Si elle est fausse, on continue l'exécution après la fin du bloc.
    • Sinon, on exécute le bloc du while, puis on recommence.
     
      google-site-verification=0bcz4aeJDJ9T3dUZ30OBJLMEF867Z1npIGezBoHmXok  
     
    Ce site web a été créé gratuitement avec Ma-page.fr. Tu veux aussi ton propre site web ?
    S'inscrire gratuitement