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.

1voto

Nordic Mainframe Points 13717

Voici ma théorie sur la raison pour laquelle la plupart des gens (y compris moi) préfèrent les boucles while(){} à do{}while() : Une boucle while(){} peut facilement être adaptée pour se comporter comme une boucle do..while() alors que l'inverse n'est pas vrai. Une boucle while est d'une certaine manière "plus générale". De plus, les programmeurs aiment les modèles faciles à saisir. Une boucle while indique dès le départ quel est son invariant et c'est une bonne chose.

Voici ce que je veux dire à propos de l'aspect "plus général". Prenez cette boucle do..while :

do {
 A;
 if (condition) INV=false; 
 B;
} while(INV);

Transformer cela en une boucle while est simple :

INV=true;
while(INV) {
 A;
 if (condition) INV=false; 
 B;
}

Maintenant, nous prenons un modèle de boucle while :

while(INV) {
     A;
     if (condition) INV=false; 
     B;
}

Et transformer cela en une boucle do..while, donne cette monstruosité :

if (INV) {
 do
 {
         A;
         if (condition) INV=false; 
         B;

 } while(INV)
}

Maintenant, nous avons deux contrôles aux extrémités opposées et si l'invariant change, vous devez le mettre à jour à deux endroits. D'une certaine manière, do..while est comme les tournevis spécialisés de la boîte à outils que vous n'utilisez jamais, car le tournevis standard fait tout ce dont vous avez besoin.

1voto

Loren Pechtel Points 5730

Je n'arrive pas à imaginer comment tu as pu rester aussi longtemps sans utiliser un do...while boucle.

Il y en a une sur un autre écran en ce moment et il y a plusieurs boucles de ce type dans ce programme. Elles sont toutes de la forme :

do
{
    GetProspectiveResult();
}
while (!ProspectIsGood());

1voto

pgast Points 1240

C'est une structure assez courante dans un serveur/consommateur :

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      REPEAT
          process
      UNTIL(wait for work(0 timeout) indicates no work)
      do what is supposed to be done at end of busy period.
   ENDIF
ENDDO

el REPEAT UNTIL(cond) être un do {...} while(!cond)

Parfois, l'attente de work(0) peut être moins coûteuse en termes de CPU (même l'élimination du calcul du délai d'attente peut être une amélioration avec des taux d'arrivée très élevés). De plus, il existe beaucoup de les résultats de la théorie des files d'attente qui font du nombre de personnes servies pendant une période d'affluence une statistique importante. (Voir par exemple Kleinrock - Vol 1).

De même :

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      set throttle
      REPEAT
          process
      UNTIL(--throttle<0 **OR** wait for work(0 timeout) indicates no work)
   ENDIF
   check for and do other (perhaps polled) work.
ENDDO

donde check for and do other work peut avoir un coût exorbitant pour être placé dans la boucle principale ou peut-être un noyau qui ne supporte pas une méthode de calcul efficace. waitany(waitcontrol*,n) ou peut-être une situation où une file d'attente prioritaire risque d'affamer le reste du travail et où l'étranglement est utilisé comme contrôle d'affamation.

Ce type d'équilibrage peut sembler être une pirouette, mais il peut être nécessaire. L'utilisation aveugle de pools de threads annulerait complètement les avantages en termes de performances de l'utilisation d'un thread gardien avec une file d'attente privée pour une structure de données compliquée à taux de mise à jour élevé, car l'utilisation d'un pool de threads plutôt que d'un thread gardien nécessiterait une implémentation thread-safe.

Je ne veux vraiment pas entrer dans un débat sur le pseudo-code (par exemple, si l'arrêt demandé doit être testé dans le UNTIL) ou sur les threads de gardien par rapport aux pools de threads - ceci est juste destiné à donner une idée d'un cas particulier d'utilisation de la structure du flux de contrôle.

1voto

chqrlie Points 17105

C'est mon opinion personnelle, mais cette question appelle une réponse fondée sur l'expérience :

  • Je programme en C depuis 38 ans, et je n'utilise jamais do / while les boucles dans le code ordinaire.

  • La seule utilisation convaincante de cette construction est dans les macros, où elle permet de regrouper plusieurs instructions en une seule via une balise do { multiple statements } while (0)

  • J'ai vu d'innombrables exemples de do / while des boucles avec une détection d'erreur bidon ou des appels de fonction redondants.

  • Mon explication pour cette observation est que les programmeurs ont tendance à modéliser les problèmes de manière incorrecte lorsqu'ils pensent en termes de do / while boucles. Soit ils manquent une condition finale importante, soit ils manquent l'échec possible de la condition initiale qu'ils déplacent à la fin.

Pour ces raisons, j'en suis venu à croire que où il y a un do / while boucle, il y a un bug et je mets régulièrement au défi les programmeurs débutants de me montrer une do / while boucle où je ne peux pas repérer un bug à proximité.

Ce type de boucle peut être facilement évité : utilisez un fichier de type for (;;) { ... } et ajouter les tests de terminaison nécessaires lorsqu'ils sont appropriés. Il n'est pas rare qu'il faille ajouter plus d'un test de ce type.

Voici un exemple classique :

/* skip the line */
do {
    c = getc(fp);
} while (c != '\n');

Cette opération échouera si le fichier ne se termine pas par une nouvelle ligne. Un exemple trivial d'un tel fichier est le fichier vide.

Une meilleure version est la suivante :

int c;  // another classic bug is to define c as char.
while ((c = getc(fp)) != EOF && c != '\n')
    continue;

Alternativement, cette version cache également le c variable :

for (;;) {
    int c = getc(fp);
    if (c == EOF || c == '\n')
        break;
}

Essayez de chercher while (c != '\n'); dans n'importe quel moteur de recherche, et vous trouverez des bugs tels que celui-ci (consulté le 24 juin 2017) :

Sur ftp://ftp.dante.de/tex-archive/biblio/tib/src/streams.c fonction getword(stream,p,ignore) , a un do / while et bien sûr, au moins deux bogues :

  • c est défini comme un char y
  • il existe une boucle infinie potentielle while (c!='\n') c=getc(stream);

Conclusion : éviter do / while des boucles et cherchez les insectes quand vous en voyez un.

0voto

Rafe Kettler Points 29389

while Les boucles vérifient la condition avant la boucle, do...while Les boucles vérifient la condition après la boucle. Ceci est utile si vous voulez baser la condition sur les effets secondaires de l'exécution de la boucle ou, comme d'autres posters l'ont dit, si vous voulez que la boucle soit exécutée au moins une fois.

Je comprends où vous voulez en venir, mais le do-while est quelque chose que la plupart des gens utilisent rarement, et que je n'ai jamais utilisé moi-même. Tu ne le fais pas mal.

Tu ne le fais pas mal. C'est comme dire que quelqu'un s'y prend mal parce qu'il n'a jamais utilisé le byte primitif. C'est juste qu'on ne l'utilise pas si souvent.

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