96 votes

"faire... pendant" ou "pendant" ?

Duplicatas possibles :
While vs. Do While
Quand dois-je utiliser les boucles do-while au lieu des boucles while ?

Je programme depuis un certain temps maintenant (2 ans de travail + 4,5 ans de diplôme + 1 an de pré-collège), et je n'ai jamais utilisé de boucle do-while avant d'y être forcé dans le cours d'introduction à la programmation. J'ai de plus en plus l'impression que je fais mal la programmation si je ne me heurte jamais à quelque chose d'aussi fondamental.

Se pourrait-il que je n'aie pas rencontré les bonnes circonstances ?

Quels sont les exemples où il serait nécessaire d'utiliser un do-while au lieu d'un while ?

(Ma scolarité s'est déroulée presque entièrement en C/C++ et mon travail est en C#, donc s'il existe un autre langage où cela a absolument du sens parce que les do-whiles fonctionnent différemment, alors ces questions ne s'appliquent pas vraiment).

Pour clarifier...je connais la différence entre un while et un do-while . While vérifie la condition de sortie et exécute ensuite les tâches. do-while effectue des tâches et vérifie ensuite les conditions de sortie.

48 votes

Pour ce que ça vaut, après une décennie de programmation dans ma carrière, j'ai utilisé une boucle do-while une ou deux fois.

0 votes

@Matt - Cela me fait me sentir mieux. Au moins, cela signifie que je ne suis pas seul.

2 votes

Je suis d'accord avec Matt et j'ajouterai une autre décennie à cela. Je n'utilise jamais la boucle do-while non plus.

0voto

Roy Berris Points 458

Même s'il y a beaucoup de réponses, voici mon point de vue. Tout se résume à l'optimisation. Je vais vous montrer deux exemples où l'un est plus rapide que l'autre.

Cas 1 : while

string fileName = string.Empty, fullPath = string.Empty;

while (string.IsNullOrEmpty(fileName) || File.Exists(fullPath))
{
    fileName = Guid.NewGuid().ToString() + fileExtension;
    fullPath = Path.Combine(uploadDirectory, fileName);
}

Cas 2 : do while

string fileName = string.Empty, fullPath = string.Empty;

do
{
    fileName = Guid.NewGuid().ToString() + fileExtension;
    fullPath = Path.Combine(uploadDirectory, fileName);
}
while (File.Exists(fullPath));

Donc ces deux-là feront exactement les mêmes choses. Mais il y a une différence fondamentale et c'est que le while nécessite une déclaration supplémentaire pour entrer dans le while. Ce qui est laid parce que disons que tous les scénarios possibles de l'instruction while sont possibles. Guid La classe a déjà été prise, sauf pour une variante. Cela signifie que je vais devoir tourner en boucle 5,316,911,983,139,663,491,615,228,241,121,400,000 temps. Chaque fois que j'arriverai à la fin de ma déclaration while, je devrai faire la procédure suivante string.IsNullOrEmpty(fileName) contrôle. Donc, cela prendrait un peu, une minuscule fraction du travail du CPU. Mais faire cette très petite tâche fois les combinaisons possibles que le Guid La classe a et nous parlons d'heures, de jours, de mois ou de temps supplémentaire ?

Bien sûr, il s'agit d'un exemple extrême car vous ne verrez probablement pas cela en production. Mais si l'on pense à l'algorithme de YouTube, il est tout à fait possible qu'il soit confronté à la génération d'un identifiant alors que certains identifiants ont déjà été pris. Il s'agit donc de grands projets et d'optimisation.

0voto

anonymoustafa Points 1

Même dans les références éducatives, vous trouverez à peine une faire...pendant que exemple. Ce n'est que récemment, après avoir lu le beau livre d'Ethan Brown, Apprendre le JavaScript J'ai rencontré un do... alors que l'exemple est bien défini. Ceci étant dit, je pense que vous pouvez vous permettre de ne pas trouver d'application pour cette structure dans votre travail de routine.

0voto

Steve Summit Points 16971

Il est vrai que do / while Les boucles sont plutôt rares. Je pense que c'est parce qu'un grand nombre de boucles sont de la forme

while(something needs doing)
    do it;

En général, il s'agit d'un excellent modèle, et il possède la propriété généralement souhaitable que si rien ne doit être fait, la boucle s'exécute zéro fois.

Mais de temps en temps, il y a une bonne raison pour laquelle vous voulez absolument faire au moins un tour dans la boucle, quoi qu'il arrive. Mon exemple préféré est le suivant : convertir un nombre entier en sa représentation décimale sous forme de chaîne de caractères, c'est-à-dire en mettant en œuvre la fonction printf("%d") ou le semi-standard itoa() fonction.

À titre d'illustration, voici une mise en œuvre relativement simple de la fonction itoa() . Ce n'est pas tout à fait la formulation "traditionnelle" ; je l'expliquerai plus en détail ci-dessous si vous êtes curieux. Mais l'essentiel est qu'il s'agit de l'algorithme canonique, qui consiste à diviser par 10 de manière répétée pour sélectionner les chiffres de droite, et qu'il est écrit à l'aide d'un programme ordinaire de type while boucle... et cela signifie qu'il a un bug.

#include <stddef.h>

char *itoa(unsigned int n, char buf[], int bufsize)
{
    if(bufsize < 2) return NULL;
    char *p = &buf[bufsize];
    *--p = '\0';

    while(n > 0) {
        if(p == buf) return NULL;
        *--p = n % 10 + '0';
        n /= 10;
    }

    return p;
}

Si vous ne l'avez pas remarqué, le bug est que ce code ne retourne rien - une chaîne vide - si vous lui demandez de convertir l'entier 0 . C'est donc un exemple de cas où, quand il n'y a "rien" à faire, on Ne le fais pas. Nous ne voulons pas que le code ne fasse rien - nous voulons toujours qu'il produise au moins un chiffre. Nous voulons donc toujours qu'il fasse au moins un tour de boucle. Ainsi, un do / while La boucle est juste le ticket :

    do {
        if(p == buf) return NULL;
        *--p = n % 10 + '0';
        n /= 10;
    } while(n > 0);

Donc maintenant nous avons une boucle qui généralement s'arrête lorsque n atteint 0, mais si n est initialement 0 - si vous passez dans un 0 - il retourne la chaîne de caractères "0" selon les besoins.

Comme promis, voici un peu plus d'informations sur l'initiative de l'UE. itoa dans cet exemple. Vous lui passez des arguments qui sont : un int à convertir (en fait, un unsigned int afin que nous n'ayons pas à nous soucier des nombres négatifs) ; un tampon dans lequel effectuer le rendu ; et la taille de ce tampon. Elle renvoie un char * pointant dans votre tampon, pointant au début de la chaîne rendue. (Ou il renvoie NULL s'il découvre que le tampon que vous lui avez donné n'était pas assez grand). L'aspect "non traditionnel" de cette implémentation est qu'elle remplit le tableau de droite à gauche, ce qui signifie qu'elle n'a pas besoin d'inverser la chaîne de caractères à la fin - et ce qui signifie également que le pointeur qu'elle vous renvoie est en général pas au début du tampon. Vous devez donc utiliser le pointeur qu'il vous renvoie comme chaîne de caractères à utiliser ; vous ne pouvez pas l'appeler et supposer ensuite que le tampon que vous lui avez remis est la chaîne de caractères que vous pouvez utiliser.

Enfin, pour être complet, voici un petit programme de test pour tester cette version de itoa avec.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int n;
    if(argc > 1)
        n = atoi(argv[1]);
    else {
        printf("enter a number: "); fflush(stdout);
        if(scanf("%d", &n) != 1) return EXIT_FAILURE;
    }

    if(n < 0) {
        fprintf(stderr, "sorry, can't do negative numbers yet\n");
        return EXIT_FAILURE;
    }

    char buf[20];
    printf("converted: %s\n", itoa(n, buf, sizeof(buf)));

    return EXIT_SUCCESS;
}

-1voto

Mikey Awbrey Points 64

Je suis tombé sur ce texte en cherchant la bonne boucle à utiliser pour une situation que j'ai rencontrée. Je pense que cela répondra pleinement à une situation courante où une boucle do while est une meilleure implémentation qu'une boucle while (langage C#, puisque vous avez déclaré que c'est votre principal travail).

Je suis en train de générer une liste de chaînes de caractères basée sur les résultats d'une requête SQL. L'objet renvoyé par ma requête est un SQLDataReader. Cet objet possède une fonction appelée Read() qui fait avancer l'objet jusqu'à la prochaine ligne de données et renvoie true s'il y a une autre ligne. Elle renvoie false s'il n'y a pas d'autre ligne.

En utilisant ces informations, je veux renvoyer chaque ligne dans une liste, puis m'arrêter lorsqu'il n'y a plus de données à renvoyer. Une boucle Do... While fonctionne le mieux dans cette situation car elle garantit que l'ajout d'un élément à la liste se fera AVANT de vérifier s'il existe une autre ligne. La raison pour laquelle cela doit être fait AVANT de vérifier la condition while(condition) est que lorsqu'elle vérifie, elle avance également. L'utilisation d'une boucle while dans cette situation entraînerait le contournement de la première ligne en raison de la nature de cette fonction particulière.

En bref :

Cela ne fonctionnera pas dans ma situation.

    //This will skip the first row because Read() returns true after advancing.
    while (_read.NextResult())
           {
               list.Add(_read.GetValue(0).ToString());
           }

   return list;

Ce sera.

    //This will make sure the currently read row is added before advancing.
    do
        {
            list.Add(_read.GetValue(0).ToString());
        } 
        while (_read.NextResult());

    return list;

-1voto

Console.WriteLine("hoeveel keer moet je de zin schrijven?");
        int aantal = Convert.ToInt32(Console.ReadLine());
        int counter = 0;

        while ( counter <= aantal)
        {
            Console.WriteLine("Ik mag geen stiften gooien");
            counter = counter + 1;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X