Accueil > Programmation Cocoa > Boucler la boucle

Boucler la boucle

Par Seth Roby le 09/09/2003

Traduit par Olivier, le 08/04/2004

Nos programmes reviennent de loin.
Vous rendez-vous compte qu’il y a encore quelques leçons de cela, nous examinions le point-virgule en fin de ligne ; maintenant nos programmes peuvent déterminer quelle action effectuer en se basant sur des critères que nous commençons à peine d’explorer ?
Nous avons fait énormément de progrès, marchant droit depuis nos humbles débuts jusque là où nous
nous trouvons maintenant.

C’est ce cheminement rectiligne que nous allons rectifier un peu aujourd’hui.
Nos programmes ne seront plus forcés de suivre un sillon tout tracé, de ligne de code en ligne de code, passant les commentaires et les blocs de conditionnelle, sans jamais regarder en arrière.
Maintenant, nous allons apprendre à nos programmes à se déplacer un peu, prendre leur temps et apprécier le code que nous avons écrit, pour évaluer ces lignes un certain nombre de fois.
Dans cette leçon, nous allons examiner la boucle.

Les boucles sont l’une des plus importante structure de programmation.
Vous utilisez les boucles pour construirer des listes et pour examiner des listes, pour lire des entrées, et Cocoa utilise les boucles pour traiter tout ce que l’utilisateur effectue.
Quand vous programmez en Cocoa, vous êtes pratiquement toujours dans une boucle.

La structure élémentaire d’une boucle est très simple et nous rappellera les conditionnelles que nous avons étudiées dans notre leçon précédente.
On y trouve un élément qui identifie le type de boucle que vous utilisez, une conditionnelle qui indique à la boucle quand s’arrêter, et un bloc de code qui est exécuté à chaque fois par la boucle.
Ces trois attributs d’une boucle définissent tout le comportement de la structure, bien que certaines boucles traitent les différentes parties un peu différemment et certains types de boucle ordonnent ces parties différemment.

La Boucle While

Les boucles while sont les types de boucles les plus simples et sont celles que vous emploierez sans doute le plus.
Quand vous commencerez à utiliser les classes Cocoa qui représentent des listes ou des groupes, vous utiliserez des boucles while associées à des NSEnumerators pour traiter tous les éléments de ces listes.
Regardons la boucle while, qui se trouve dans une nouvelle fonction que nous pouvons ajouter à notre programme.

void countTo(int loopsToPerform) {
    int loopsPerformed = 1;
    printf("Let's count up to my favorite number!n");

    while(loopsPerformed <= loopsToPerform) {    //loop while we are counting
        printf("%d!n", loopsPerformed);
        loopsPerformed++;    //keep counting
    }

    printf("That's it! My favorite number is %d!!!n", loopsToPerform);
}

Etudions d’abord le code avant de le greffer à notre programme.
Premièrement, notez que le code de la boucle que nous étudions se trouve dans une définition de fonction que nous connaissons depuis la deuxième leçon.
Le type de la valeur retournée est nouveau : void.
Ce type est spécial ; il signifie que la fonction ne retourne aucune valeur, et que donc le retour doit être ignoré (si vous essayer de définir une valeur de variable à retourner par la fonction void, vous obtiendrez une warning.)

Maintenant que nous savons comment est structuré le cadre des fenêtres, nous pouvons regarder à travers les vitres.
Nous commençons avec une définition de variable, puis un printf qui annonce notre intention à l’utilisateur.
Nous avons une boucle while, puis un printf qui indique ce nous avons fait.
Que fait donc la boucle while, et comment fonctionne-t-elle ?

Elle commence par un élément while, puis quelque chose entre parenthèses, puis un bloc de code qui définit ce que l’ordinateur devrait exécuter dans la boucle.
La magie se situe entre les parenthèses, qui contient la maintenant familière conditionnelle.
Le code va continuer à effectuer la boucle tant que la condition est TRUE.
Tant que la condition est évaluée à autre chose que FALSE (c.à.d. zéro), l’ordinateur exécutera la boucle.

La manière la plus simple d’y penser est de dire que l’ordinateur considère toute la structure while comme une ligne de code complexe.
Quand il arrive à cette ligne, il évalue la conditionnelle.
Si la condition est FALSE, l’ordinateur se déplace jusqu’à la prochaine ligne de code située après la boucle while.
Mais si la condition est TRUE, il exécute le code à l’intérieur du bloc.
Cette exécution est appelée une itération, qui définit une passe dans la boucle.
Quand l’ordinateur arrive en fin de bloc, il vérifie de nouveau la condition, et si elle est toujours TRUE, il effectue une autre itération, encore et encore jusqu’à ce que la condition soit FALSE.

Le code que nous avons dans notre bloc imprime des lignes de texte, contenant le nombre courant.
Puis il incrémente la variable loopsPerformed.
Donc, à chaque itération à travers la boucle, il affiche jusqu’où il a compté, et ajoute un.
Cet incrément indique comment évolue la boucle depuis son début jusqu’à sa fin.
Sans lui, votre boucle ne pourrait jamais se terminer.
Et à chaque itération, la condition vérifie que le nombre de boucles que nous avons effectuées est inférieur ou égal (c’est le ‘<=’) au nombre total de boucle à effectuer.
Notre condition est TRUE tant que nous comptons, et fausse dès que nous avons compté au-delà de ça.

Ajoutons notre nouvelle fonction à notre projet, à la fin de notre fichier main.c.
Rappelez-vous de rajouter une déclaration de fonction en haut du fichier, comme cela :

void countTo(int loopsToPerform);

Maintenant, retirons de notre fonction main la ligne de code qui disait :

printf("My favorite number is %d!", favoriteNumber);

Et remplaçons-la par cette ligne :

countTo(favoriteNumber);

Cela devrait nous permettre de lancer notre programme.
Vous verrez alors comme votre ordinateur est rapide.

Boucle Do…While

Il y a une petite chose que while fait qui peut parfois s’avérer ennuyant : il vérifie la condition chaque fois que vous effectuez la boucle, de la première à la dernière fois.
Il semble que ce soit exactement ce que vous souhaitez, mais parfois vous souhaitez avoir un code qui est toujours au moins exécuté une fois, et qui est répété si la condition est vraie.
Pour ce cas précis (que vous n’utiliserez pas souvent), C propose la boucle do…while, qui ressemble à :

void countTo(int loopsToPerform) {
    int loopsPerformed = 0;
    printf("What's my favorite number?n");

    do {        //we want to always rule out one number
        printf("It sure isn't %d...n", loopsPerformed);
        loopsPerformed++;
    } while (loopsToPerform >= loopsPerformed);

    printf("%d is my favorite number!n", loopsToPerform);
}

Les choses ont un peu été modifiées, mais la structure de base est similaire à celle de notre code précédent.
La modification importante se trouve là où la boucle while se transforme en boucle do…while.
Voyons cela plus en détail.

Nous commençons notre boucle par un élément do.
Ceci indique à l’ordinateur que le bloc d’après doit impérativement être exécuté.
Après le bloc, nous trouvons l’élément while, puis une condition entre parenthèses.
Remarquez que nous avons modifié notre condition et que nous comparons maintenant avec l’opérateur plus grand que ou égal (le ‘>=’), mais comme nous avons également modifié l’ordre des variables dans la condition, il s’agit du même test.

Puisqu’il n’y a rien de spécial au niveau de cette boucle, nous allons explorer un peu plus au niveau des boucles et de la programmation en général.
Commençons par faire quelque chose que nous ne sommes pas censés faire (ce qui veut dire que vous ne devriez pas exécuter ce qui suit) :

void countTo(int loopsToPerform) {
    int loopsPerformed = 0;
    printf("What's my favorite number?n");

    do {
        printf("It sure isn't %d...n", loopsPerformed);
        loopsPerformed++;
    } while (1);

    printf("%d is my favorite number!n", loopsToPerform);
}

Nous avons remplacé notre condition par la constante 1.
Ceci signifie que notre boucle est exécuté jusqu’à ce que 1 puisse être évaluer à 0, ce qui n’arrivera jamais.
Ceci est un exemple de boucle infinie.
Vous avez demandé à l’ordinateur d’exécuter cette boucle pour toujours, effectuant ces impressions pendant tout ce temps.

Vous remarquerez, avec l’expérience, qu’un ordinateur effectue toujours littéralement ce que vous lui demandez, parce qu’il n’a aucun moyen d’interpréter votre instruction autrement que littéralement : il ne peut pas rattraper vos erreurs et ne remarquera pas la nuance dans le son de votre voix.
La programmation (dans les langages impératifs du moins comme le C et ses dérivés) est le processus par lequel vous énoncez exactement ce que vous souhaitez que l’ordinateur effectue et dans quel ordre.
Vous indiquez tout à l’ordinateur, depuis l’affichage à l’écran jusqu’à l’écriture dans un fichier.
Nous utilisons des fonctions comme printf, une fonction C, pour nous éviter d’effectuer tout ce travail de bas niveau, mais nous nous appuyons sur le travail déjà effectué par d’autre, parce que nous ne voulons pas “réinventer la roue” comme disent les programmeurs.
Si le travail est déjà fait, utilisez-le, et ne le refaites pas.
Le code que vous écrivez contient des boucles ; votre développement ne devrait pas.
Eviter de tomber dans le piège de réinventer la roue s’appelle la “réutilisation de code”, et c’est une pratique très courante et une preuve d’un code bien conçu.

La puissance de Cocoa tient dans ce que même les tâches les plus simples –ainsi que certaines des plus avancées– sont déjà programmées et n’attendent que vous, et vous n’avez qu’à indiquer à l’ordinateur que faire quand vous traitez des choses spécifiques à votre programme.
Pour l’instant, vous pouvez en apercevoir un petit bout en notant le nombre de fois que nous utilisons printf, ou combien de fois chaque application Mac utilise une simple fonctionnalité de Cocoa, une petite chose appelé fenêtre.

Mais avant de rêver aux choses à venir, voyons comment nous pouvons corriger la pagaille que nous avons mise :

void countTo(int loopsToPerform) {
    int loopsPerformed = 0;
    printf("What's my favorite number?n");

    do {
        printf("It sure isn't %d...n", loopsPerformed);
        loopsPerformed++;
        if (loopsPerformed == loopsToPerform) {
            break;
        }
    } while (1);

    printf("%d is my favorite number!n", loopsToPerform);
}

Nous avons ajouté une petite condition pour vérifier si nous avons suffisamment compté, et si nous y sommes arrivés, il utilisera l’instruction break que nous avons utilisée dans la leçon 3 pour sortir du switch, seulement maintenant, nous l’utilisons pour sortir d’une boucle.
Quand l’ordinateur trouve un break, il arrête le processus d’itération de la boucle dans laquelle il se trouve.
S’il y a une boucle à l’intérieur d’une autre boucle (une boucle imbriquée), il sortira de la boucle la plus intérieure.
Voici une autre manière d’empêcher que notre code bancal ne devienne un sérieux problème (encore une fois, vous pouvez exécuter ceci) :

void countTo(int loopsToPerform) {
    int loopsPerformed = 0;
    printf("What's my favorite number?n");

    do {
        printf("It sure isn't %d...n", loopsPerformed);
        loopsPerformed++;
        if (loopsPerformed < loopsToPerform) {
            //more counting to be done
            continue;
        }
        break;
    } while (1);

    printf("%d is my favorite number!n", loopsToPerform);
}

Ici, nous avons ajouté un break à la fin de notre boucle qui nous fera sortir, mais nous avons également ajouté une conditionnelle pour vérifier notre compte.
Dans cette conditionnelle, nous avons la commande continue, qui nous force dans l’itération suivante sans terminer celle-ci.
Donc quand le décompte n’est pas terminé, nous remontons en haut du bloc, sans passer par l’instruction break.

Vous pensez certainement qu’il s’agit d’une façon stupide de régler les choses, et nous devrions utiliser la condition de boucle comme c’était le cas au début, et vous avez raison.
Continuez à penser comme cela, et votre code sera agréable à lire.

Pour Toute Boucle il y a une Condition

La dernière boucle que nous allons voir est la boucle for.
Quand vous devez traiter une liste de nombres, les boucles for vous permettent de gagner du temps.
Et quand vous devez traiter des entiers, vous utilisez généralement la boucle for.
Regardons le code utiliser pour la démonstration de la boucle while :

void countTo(int loopsToPerform) {
    int loopsPerformed = 1;
    printf("Let's count up to my favorite number!n");

    while(loopsPerformed <= loopsToPerform) {    //loop while we're counting
        printf("%d!n", loopsPerformed);
        loopsPerformed++;    //keep counting
    }

    printf("That's it! My favorite number is %d!!!n", loopsToPerform);
}

Et voici une version simplifiée utilisant la boucle for :

void countTo(int loopsToPerform) {
    int loopsPerformed;
    printf("Let's count up to my favorite number!n");

    for(loopsPerformed = 1; loopsPerformed <= loopsToPerform; loopsPerformed++) {
        printf("%d!n", loopsPerformed);
    }

    printf("That's it! My favorite number is %d!!!n", loopsToPerform);
}

L’idée de base de le boucle for est de prendre le code qui est logiquement lié à la boucle et le déplacer là où il est plus lié visuellement.
La condition d’une boucle for prend ainsi trois différents rôles, que nous allons examiner dans l’ordre.
Chaque rôle possède sa propre section à l’intérieur des parenthèses, qui est séparée des autres par des points-virgules.

La première section est pour l’initialisation.
Elle est évaluée une fois pour toute quand le programme entre pour la première fois dans la boucle for (à moins que le programme ne revienne à cette boucle).
Ici, vous pouvez donner une valeur à la variable qui sera utilisée comme un compteur, en utilisant généralement l’opérateur d’assignement.
Si vous ne voulez pas initialiser de valeur, laissez cette section vide.

La section du milieu est une condition.
Elle agit comme la condition de la boucle while : la boucle continuera d’être exécutée tant que la condition est vraie.
Tout comme dans une boucle while, elle est évaluée chaque fois au début de l’itération pour voir si la boucle doit être ou non exécutée.

La dernière section est l’incrément, tout comme nous l’avons vu dans les boucles while et do…while.
Cette section est évaluée chaque fois que la boucle complète une itération, avant que la condition ne soit évaluée.

Ces trois sections–initialisation, condition et l’incrément–créent l’environnement de la boucle for.
Copiez ce bout de code et remplacez la fonction countTo, et exécutez le programme pour voir que, même si le code a changé, la fonctionnalité du programme n’a pas changé par rapport à la boucle while.

Notez cependant que ce n’est pas toujours le cas.
Il y a des choses que vous pouvez faire avec une boucle while qu’il n’est pas possible de faire avec une boucle for, comme effectuer plusieurs actions avant d’arriver à la prochaine itération, ou initialiser plusieurs variables.
En géneral, une boucle for est une solution moins flexible pour résoudre les même problèmes que la boucle while, mais il est pour l’instant difficile de voir la différence, parce que nos connaissances sur les types de variables nous limitent pour l’instant au décompte.

Plus de Types Que Vous ne Pouvez en Compter

Nous avons maintenant compris les différents types de boucles et avons une idée des différences entre eux.
Dans notre prochaine leçon nous verrons plus en détail les variables et nous introduirons quelques nouveaux types qui nous permettrons de faire une meilleure disctinction entre les boucles for et while, ainsi que la manière d’exprimer de nouveaux concepts qui ne pourraient pas l’être avec des entiers.
Bien que nous ayons parlé des variables auparavant, et que nous les avons utilisées dans toutes les lignes de code que nous avons écrites jusqu’à présent (enfin, pas les lignes n’ayant simplement qu’une parenthèse), nous ne savons pas exactement ce que ces petits bouts de données sont et comment nous pouvons interagir avec.
Nous verrons comment on les fabrique, où elles vivent, et bien plus dans notre prochaine leçon.

Textes originaux en anglais sur O’Reilly : Loop the Loop par Seth Roby

opoppon Programmation Cocoa , ,

  1. Pas encore de commentaire
  1. Pas encore de trackbacks
Vous devez être identifié pour poster un commentaire