'hacer ... mientras' frente a 'mientras'


86

Posibles duplicados:
While vs. Do While ¿
Cuándo debo usar los bucles do-while en lugar de while?

He estado programando por un tiempo (2 años de trabajo + 4.5 años de grado + 1 año de preuniversitario), y nunca he usado un ciclo de hacer mientras no me veo obligado a hacerlo en el curso de Introducción a la programación. Tengo la sensación de que estoy haciendo mal la programación si nunca me encuentro con algo tan fundamental.

¿Podría ser que simplemente no me he encontrado con las circunstancias correctas?

¿Cuáles son algunos ejemplos en los que sería necesario utilizar un do-while en lugar de un while?

(Mi educación fue casi toda en C / C ++ y mi trabajo está en C #, por lo que si hay otro lenguaje en el que tiene absolutamente sentido porque los do-whiles funcionan de manera diferente, entonces estas preguntas realmente no se aplican).

Para aclarar ... sé la diferencia entre a whiley a do-while. Mientras comprueba la condición de salida y luego realiza tareas. do-whilerealiza tareas y luego verifica la condición de salida.


42
Por lo que vale, después de una década de programación como mi carrera, he usado un ciclo de hacer mientras una o dos veces.
Matt Greer

@Matt - Eso me hace sentir mejor. Al menos significa que no estoy solo.
mphair

2
Secundaré a Matt y agregaré otra década más o menos a eso. Rara vez utilizo el bucle do-while.
quentin-starin

MUCHOS duplicados. Aquí hay uno que enlaza con un montón de ellos: stackoverflow.com/questions/3094972/…
gnovice

3
La "pregunta maestra" correcta parece ser stackoverflow.com/questions/224059/…
Donal Fellows

Respuestas:


115

Si siempre desea que el bucle se ejecute al menos una vez. No es común, pero lo uso de vez en cuando. Un caso en el que es posible que desee utilizarlo es intentar acceder a un recurso que podría requerir un reintento, por ejemplo

do
{
   try to access resource...
   put up message box with retry option

} while (user says retry);

3
Así que supongo que esto seguiría bajo el "No me he encontrado con esa circunstancia".
mphair

7
Honestamente, rara vez me encuentro con una circunstancia en la que solo necesito usar un do .. mientras ..
Stan R.

1
Quizás un poco corto, pero Bob tiene razón. Do / while debe usarse cuando desee ejecutar el bloque de código al menos una vez . Debe usar un ciclo while cuando no sepa si desea ejecutarlo una sola vez. Dicho esto, puedo decirles que con alrededor de 15 años de experiencia en desarrollo, he usado muchas veces más bucles while que bucles do / while.
ConsultUtah

1
También los he usado de vez en cuando, aunque rara vez. Después de un rato, por lo general, también se refactorizan en un ciclo while normal, solo porque las áreas a su alrededor cambiaron y funcionaron ... aunque más torpes de lo que eran al principio.
Joshua

2
Es bastante común. Pero no veo por qué en su ejemplo no usaría un bucle while. Y no veo por qué esta respuesta está siendo votada a favor.

65

do-while es mejor si el compilador no es competente en la optimización. do-while tiene un solo salto condicional, a diferencia de for y while que tienen un salto condicional y un salto incondicional. Para las CPU que están canalizadas y no hacen predicción de ramas, esto puede marcar una gran diferencia en el rendimiento de un ciclo cerrado.

Además, dado que la mayoría de los compiladores son lo suficientemente inteligentes como para realizar esta optimización, todos los bucles que se encuentran en el código descompilado serán usualmente do-while (si el descompilador se molesta siquiera en reconstruir los bucles a partir de gotos locales hacia atrás).


5
+1 para agregar información técnica relevante a la elección entre formas de bucle.
quentin-starin

2
No solo prematuro sino inútil. Si realmente deseaba un bucle while, es decir, la capacidad de iterar 0 veces, debe encerrar el bucle en un if, lo que devuelve ese salto.
JeremyP

3
@Jeremy: El salto del que hablas está fuera del ciclo, no se ejecuta N veces.
Ben Voigt

1
Considere también el uso clásico de do-while en el dispositivo de Duff (en el que un bucle while se transforma en un do-while desenrollado con un paso más grande más una tabla de salto para manejar el resto) que reduce drásticamente la sobrecarga del bucle, en aplicaciones como memset, memcmp, memcpy puede aumentar el rendimiento en un factor de 10.
Ben Voigt

@BenVoigt Sé que su comentario tiene ya una década, pero el dispositivo de Duff no debería mencionarse sin una advertencia muy importante: se ha vuelto menos eficiente en los compiladores modernos, porque los compiladores modernos generalmente pueden desenrollar de manera inteligente los bucles sencillos como óptimos para la máquina de destino. , aunque generalmente no tienen lógica para averiguar la intención de un dispositivo Duff y, por lo tanto, no pueden optimizarlo tan bien. Lo cual es una gran lección sobre cómo optimizar el código para alguna máquina de destino en lugar de para un "optimizador suficientemente avanzado" abstracto.
mtraceur

12

He usado esto en una función TryDeleteDirectory. Fue algo como esto

do
{
    try
    {
        DisableReadOnly(directory);
        directory.Delete(true);
    }
    catch (Exception)
    {
        retryDeleteDirectoryCount++;
    }
} while (Directory.Exists(fullPath) && retryDeleteDirectoryCount < 4);

Agradable. Este es el primer ejemplo que tiene sentido estar envuelto en un do ... while.
Joshua

4
¿Por qué / cómo es esto mejor que un estándar while?
Josh Stodola

El ciclo siempre se ejecutará una vez, por lo que es posible que desee hacer algo y luego intentarlo de nuevo si falla. Si utiliza un ciclo while normal, comprobará si falla incluso antes de haberlo hecho en la primera iteración.
NibblyPig

1
@SLC ¿Pero no le gustaría comprobar si el directorio existe de antemano de todos modos?
Josh Stodola

1
@Josh En este ejemplo, sí. Pero si estuviera intentando abrir una conexión a un servidor ocupado, se conectaría primero y vería si la respuesta estaba "ocupada". Si lo fuera, lo volvería a intentar varias veces antes de darse por vencido.
NibblyPig

11

Do while es útil para cuando quieres ejecutar algo al menos una vez. En cuanto a un buen ejemplo para usar do while versus while, digamos que desea hacer lo siguiente: Una calculadora.

Puede abordar esto utilizando un bucle y verificando después de cada cálculo si la persona quiere salir del programa. Ahora probablemente pueda asumir que una vez que se abre el programa, la persona quiere hacer esto al menos una vez, por lo que podría hacer lo siguiente:

do
{
    //do calculator logic here
    //prompt user for continue here
} while(cont==true);//cont is short for continue

2
En realidad, ahora que lo mencionas, cualquier tipo de interfaz basada en menús basada en consola funcionaría bien en un bucle do ... while también. Por ejemplo, solicitar opciones (una tecla a la vez) y salir solo cuando eligen continuar o salir.
Joshua

7
continuees una palabra clave; D
Thomas Eding

Atrinithis: Lol ... Me equivoqué. Gracias por corregirme ahí.

== trueno es necesario. cont == truesi cont es verdadero, devuelve verdadero. Eso es totalmente inútil.
Mr.DeleteMyMessages

11

Esta es una especie de respuesta indirecta, pero esta pregunta me hizo pensar en la lógica detrás de ella, y pensé que valdría la pena compartirla.

Como han dicho todos los demás, usa un do ... whilebucle cuando desea ejecutar el cuerpo al menos una vez. Pero, ¿bajo qué circunstancias le gustaría hacer eso?

Bueno, la clase de situaciones más obvia en la que puedo pensar sería cuando el valor inicial ("sin cebar") de la condición de verificación es el mismo que cuando desea salir . Esto significa que debe ejecutar el cuerpo del bucle una vez para cebar la condición a un valor no existente y luego realizar la repetición real basada en esa condición. Con los programadores siendo tan vagos, alguien decidió envolver esto en una estructura de control.

Entonces, por ejemplo, leer caracteres desde un puerto serie con un tiempo de espera podría tomar la forma (en Python):

response_buffer = []
char_read = port.read(1)

while char_read:
    response_buffer.append(char_read)
    char_read = port.read(1)

# When there's nothing to read after 1s, there is no more data

response = ''.join(response_buffer)

Tenga en cuenta la duplicación de código: char_read = port.read(1) . Si Python tuviera un do ... whilebucle, podría haber usado:

do:
    char_read = port.read(1)
    response_buffer.append(char_read)
while char_read

El beneficio adicional para los lenguajes que crean un nuevo alcance para los bucles: char_readno contamina el espacio de nombres de la función. Pero tenga en cuenta también que hay una mejor manera de hacer esto, y es utilizando el Nonevalor de Python :

response_buffer = []
char_read = None

while char_read != '':
    char_read = port.read(1)
    response_buffer.append(char_read)

response = ''.join(response_buffer)

Así que aquí está el quid de mi punto: en los lenguajes con tipos que aceptan valores NULL, la situación initial_value == exit_valuesurge con mucha menos frecuencia y es posible que esa sea ​​la razón por la que no la encuentre. No digo que nunca suceda, porque todavía hay momentos en los que una función volveráNone a significar una condición válida. Pero en mi opinión apresurada y brevemente considerada, esto sucedería mucho más si los lenguajes que utilizó no permitieran un valor que signifique: esta variable aún no se ha inicializado.

Este no es un razonamiento perfecto: en realidad, ahora que los valores nulos son comunes, simplemente forman un elemento más del conjunto de valores válidos que puede tomar una variable. Pero prácticamente, los programadores tienen una forma de distinguir entre una variable que está en estado sensible, que puede incluir el estado de salida del bucle, y que está en un estado no inicializado.


Esta es una de las respuestas más interesantes que he leído aquí. Buena contribución.
Bob Moore

Las dos versiones no son equivalentes. Si la primera lectura regresa None, la whileversión correctamente no agrega nada al búfer de respuesta, pero su doversión siempre agrega algo.
David Stone

@DavidStone read()no debería volver nunca None. Si está utilizando una biblioteca donde lo hace, la premisa no se aplica (es decir, que el valor centinela no está en el conjunto de posibles valores de verificación).
2016

Con su última edición, veo lo que debería haber dicho en ''lugar de None. Algún tipo de valor que se evalúa como falso. Lo atribuyo a mi falta de familiaridad con la readfunción de Python .
David Stone

@DavidStone No lo entiendo. Si read()regresa '', no se agregará nada a la cadena, está vacío.
2016

7

Los usé bastante cuando estaba en la escuela, pero no tanto desde entonces.

En teoría, son útiles cuando desea que el cuerpo del bucle se ejecute una vez antes de la verificación de la condición de salida. El problema es que para los pocos casos en los que no quiero la verificación primero, normalmente quiero la verificación de salida en el medio del cuerpo del bucle en lugar de al final. En ese caso, prefiero usar el conocido for (;;)con alguna if (condition) exit;parte del cuerpo.

De hecho, si estoy un poco tembloroso en la condición de salida del bucle, a veces me resulta útil comenzar a escribir el bucle for (;;) {}con una declaración de salida donde sea necesario, y luego, cuando termine, puedo ver si puede ser " limpiado "moviendo las inicializaciones, las condiciones de salida y / o el código de incremento forentre paréntesis.


5
Por curiosidad ... ¿por qué "for (;;)" en lugar de "while (true)"?
mphair

4
Probablemente solo pruebe. He llegado a equipararme for(;;)con "bucle infinito", mientras while(true)que tengo que detenerme y pensar. Quizás sea porque estaba codificando C antes de que existiera un true. En el pasado, solo teníamos TRUEuna macro, y si algo tenía errores, tendría que convencerme de que la macro no se ha redefinido de 0alguna manera (¡sucedió!). Con for(;;)no hay posibilidad de eso. Si insistes en el formulario while, casi prefiero ver while (1). Por supuesto, algunos podrían preguntarse si no es la letra l ...
TED

1
@mphair: Sí, si toma nota del texto que pone el editor cuando escribe en cursiva o escribe elcodeify texto, puede escribirlo directamente en el campo de comentarios usted mismo. He visto a algunas personas poner hipervínculos, pero eso es demasiado duro para mí.
TED

2
@TED: Mi notación preferida para bucle-hasta-salida-explícita es "do {} while (1);". Por cierto, en el trabajo de sistemas embebidos, mi paradigma de bucle normal es "i = 10; do {} while (- i);". Para bucles estrechos, eso es mucho más rápido que un típico for (); Supongo que es más legible usar eso de manera consistente como patrón de bucle cuando no se necesita un conteo ascendente que usar arbitrariamente for () en casos que no son críticos para el rendimiento.
supercat

2
Agregando a la confusión while (1) y for (;;), he visto código usando for (EVER) con EVER definido como ;;
asr

6

Una situación en la que siempre es necesario ejecutar un fragmento de código una vez y, según el resultado, posiblemente más veces. Lo mismo se puede producir con un whilebucle regular .

rc = get_something();
while (rc == wrong_stuff)
{
    rc = get_something();
}

do
{
    rc = get_something();
}
while (rc == wrong_stuff);

6

do whilees si desea ejecutar el bloque de código al menos una vez. whilepor otro lado, no siempre se ejecutará según los criterios especificados.


5

Es tan simple como eso:

condición previa vs condición posterior

  • while (cond) {...} - condición previa, ejecuta el código solo después de verificarlo.
  • do {...} while (cond) - condición posterior, el código se ejecuta al menos una vez.

Ahora que conoces el secreto ... úsalos sabiamente :)


1
Como dije, sé cómo funcionan, pero no estaba seguro de en qué caso uno tiene sentido sobre el otro.
mphair

Es lógico que use el do {} mientras sabe con certeza que tiene que pasar al menos una vez por el ciclo. Como, por ejemplo, si tiene una función que encuentra un elemento en una matriz y previamente ha puesto una matriz if. . Si pasó esa verificación, puede usar do {} while. Do-while también es fácil de considerar, como un ciclo repetitivo: "Yo como hasta que estoy satisfecho" se traduce como hacer {comer ();} while (! satisfecho ();). Probar la condición antes del bucle se considera más seguro ... y por eso se usa con más frecuencia.
Ioan Paul Pirau

4

Veo que esta pregunta ha sido respondida adecuadamente, pero me gustaría agregar este escenario de caso de uso muy específico. Puede comenzar a usar do ... while con más frecuencia.

do
{
   ...
} while (0)

se utiliza a menudo para #defines de varias líneas. Por ejemplo:

#define compute_values     \
   area = pi * r * r;      \
   volume = area * h

Esto funciona bien para:

r = 4;
h = 3;
compute_values;

-pero- hay una trampa para:

if (shape == circle)  compute_values;

ya que esto se expande a:

if (shape == circle) area = pi *r * r;
volume = area * h;

Si lo envuelve en un bucle do ... while (0), se expande correctamente a un solo bloque:

if (shape == circle)
  do
  {
    area = pi * r * r;
    volume = area * h;
  } while (0);

2

Hasta ahora, las respuestas resumen el uso generalizado para hacer mientras. Pero el OP pidió un ejemplo, así que aquí hay uno: Obtenga la entrada del usuario. Pero la entrada del usuario puede no ser válida, por lo que solicita la entrada, la valida, procede si es válida, de lo contrario, repita.

Con do-while, obtiene la entrada mientras que la entrada no es válida. Con un ciclo while regular, obtienes la entrada una vez, pero si no es válida, la obtienes una y otra vez hasta que sea válida. No es difícil ver que el primero es más corto, más elegante y más simple de mantener si el cuerpo del bucle se vuelve más complejo.


Creo que la razón por la que nunca los he usado para esto es que por lo general termino diciéndole al usuario lo que estaba mal con su entrada. Lo que significa que el condicional estaría en el centro de un bucle y lo haría solo breaksi la entrada es correcta.
mphair

@mphair: En realidad, para ese tipo de situación, a veces podría estar más inclinado a usar un "do {} while (0);" bucle, usando "continuar"; si la entrada del usuario es inaceptable. Si solo hay un problema y un mensaje, use "do {} while (1);" y "romper"; funciona bien, pero si hay varias razones para exigir el reingreso, el "continuar"; La construcción funciona mejor.
supercat

2

Lo he usado para un lector que lee la misma estructura varias veces.

using(IDataReader reader = connection.ExecuteReader())
{
    do
    {
        while(reader.Read())
        {
            //Read record
        }
    } while(reader.NextResult());
}

1

He usado un do whilecuando leo un valor centinela al comienzo de un archivo, pero aparte de eso, no creo que sea anormal que esta estructura no se use con demasiada frecuencia, los do-whiles son realmente situacionales.

-- file --
5
Joe
Bob
Jake
Sarah
Sue

-- code --
int MAX;
int count = 0;
do {
MAX = a.readLine();
k[count] = a.readLine();
count++;
} while(count <= MAX)

1

Esta es mi teoría de por qué la mayoría de la gente (incluyéndome a mí) prefiere bucles while () {} para hacer {} while (): Un bucle while () {} se puede adaptar fácilmente para que funcione como un bucle do.. while () mientras que lo contrario no es verdad. Un bucle while es en cierto modo "más general". También a los programadores les gustan los patrones fáciles de entender. Un ciclo while dice desde el principio cuál es su invariante y esto es algo bueno.

Esto es lo que quiero decir con lo "más general". Toma este bucle do.. while:

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

Transformar esto en un bucle while es sencillo:

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

Ahora, tomamos un modelo while loop:

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

Y transformar esto en un bucle do.. while, produce esta monstruosidad:

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

 } while(INV)
}

Ahora tenemos dos comprobaciones en los extremos opuestos y si el invariante cambia, debe actualizarlo en dos lugares. En cierto modo, do.. while es como los destornilladores especializados en la caja de herramientas que nunca usa, porque el destornillador estándar hace todo lo que necesita.


1
Reemplazando un "hacer {} mientras (x);" bucle en un "while (x);" El bucle requiere que X sea una condición que pueda ser fácilmente "preparada" o que sea "naturalmente" verdadera en la primera pasada. Para mí, las declaraciones de cebado antes de un ciclo implican que algo dentro del ciclo necesita cebado, y un ciclo while (x) {}; "implica que el ciclo puede ejecutarse cero veces. Si quiero un ciclo que se ejecute al menos una vez, use un bucle "do {} while (x);".
supercat

1

Estoy programando alrededor de 12 años y hace solo 3 meses me encontré con una situación en la que era realmente conveniente usar do-while ya que siempre era necesaria una iteración antes de verificar una condición. Así que supongo que su gran momento está por venir :).


1
Casi todas las veces que he visto un do ... mientras que fue por una falta de comprensión del problema e involucró algún truco terrible. Hay excepciones, pero en general , si tienes algo que hacer ... mientras, deberías reconsiderar lo que estás haciendo ... :-)
Brian Knoblauch

2
Si estaba en lo correcto, entonces do-while sería excluido de todos los lenguajes de programación para no confundir a los programadores :).
Narek

@Narek: Han pasado casi siete años más desde que escribiste esto, ¿has tenido más circunstancias en las que do whilehabía una mejor solución sin remordimientos?
chqrlie

Sí, probablemente una vez más: D
Narek

1

No puedo imaginar cómo has pasado tanto tiempo sin usar un do...whilebucle.

Hay uno en otro monitor en este momento y hay varios bucles de este tipo en ese programa. Son todos de la forma:

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

1

Es una estructura bastante común en un servidor / consumidor:

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)ser undo {...} while(!cond)

A veces, la espera para el trabajo (0) puede ser más barata en cuanto a CPU (incluso eliminar el cálculo del tiempo de espera podría ser una mejora con tasas de llegada muy altas). Además, hay muchos resultados de la teoría de las colas que hacen que el número servido en un período ocupado sea una estadística importante. (Ver, por ejemplo, Kleinrock - Vol 1.)

Similar:

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 workpuede ser exorbitantemente caro poner en el bucle principal o quizás un kernel que no admite una waitany(waitcontrol*,n)operación de tipo eficiente o quizás una situación en la que una cola priorizada podría privar al otro trabajo y se usa el acelerador como control de inanición.

Este tipo de equilibrio puede parecer un truco, pero puede ser necesario. El uso ciego de grupos de subprocesos anularía por completo los beneficios de rendimiento del uso de un subproceso cuidador con una cola privada para una estructura de datos complicada de alta tasa de actualización, ya que el uso de un grupo de subprocesos en lugar de un subproceso cuidador requeriría una implementación segura para subprocesos.

Realmente no quiero entrar en un debate sobre el pseudocódigo (por ejemplo, si el apagado solicitado debe probarse en el HASTA) o los subprocesos del cuidador frente a los grupos de subprocesos; esto solo tiene la intención de dar una idea de un caso de uso particular de la estructura del flujo de control.


1

Esta es mi opinión personal, pero esta pregunta pide una respuesta basada en la experiencia:

  • He estado programando en C durante 38 años y nunca uso do/ whileloops en código regular.

  • El único uso convincente de esta construcción es en macros donde puede envolver múltiples declaraciones en una sola declaración a través de un do { multiple statements } while (0)

  • He visto innumerables ejemplos de do/ whileloops con detección de errores falsos o llamadas a funciones redundantes.

  • Mi explicación para esta observación es que los programadores tienden a modelar los problemas incorrectamente cuando piensan en términos de bucles do/ while. O pasan por alto una condición final importante o pasan por alto el posible fallo de la condición inicial que mueven al final.

Por estas razones, he llegado a creer que donde hay un do/ whileloop, hay un error , y regularmente desafío a los programadores novatos a que me muestren un do/ whileloop donde no puedo detectar un error cercano.

Este tipo de bucle se puede evitar fácilmente: utilice ay for (;;) { ... }agregue las pruebas de terminación necesarias donde sea apropiado. Es bastante común que sea necesario realizar más de una prueba de este tipo.

Aquí hay un ejemplo clásico:

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

Esto fallará si el archivo no termina con una nueva línea. Un ejemplo trivial de tal archivo es el archivo vacío.

Una mejor versión es esta:

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

Alternativamente, esta versión también oculta la cvariable:

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

Intenta buscar while (c != '\n'); en cualquier motor de búsqueda y encontrará errores como este (recuperado el 24 de junio de 2017):

En ftp://ftp.dante.de/tex-archive/biblio/tib/src/streams.c , la función getword(stream,p,ignore)tiene un do/ whiley , efectivamente , al menos 2 errores:

  • cse define como una chary
  • hay un bucle infinito potencial while (c!='\n') c=getc(stream);

Conclusión: evite do/ whileloops y busque errores cuando vea uno.


1
Prefiero evitar los while() {}bucles, porque son más seguros en términos de comprobaciones iniciales, por lo que tiende a hacer que se "pierda el cerebro", que sea perezoso para pensar en un algoritmo mejor, que ponga un montón de comprobaciones de errores innecesarias, etc. "Falta de do{}while()uso" es una señal de programador malo (descerebrado) o novato, produce un código más lento y de menor calidad. Así que primero me pregunto "¿Es estrictamente un caso while () {}?" Si no, solo intentaré escribir el bucle do while, a pesar de que podría requerir más pensamiento y precisión de datos de entrada
xakepp35

Entiendo su respuesta, pero podría pensar en algunos escenarios posibles en los que esto realmente sería mejor. Mire while: prnt.sc/v2zy04 o do while: prnt.sc/v2zyka . No he sido programador durante tanto tiempo como tú, pero no pude encontrar un error allí. Está bastante claro que el do while es más limpio porque no requiere la verificación adicional del while para ingresar al ciclo. Si estamos hablando de optimizar el código, diría que está bastante limpio.
Roy Berris

@RoyBerris: tu ejemplo es interesante. En un programa en C, las funciones utilizadas dentro del ciclo requerirían pruebas adicionales para asegurarse de que no fallaran. Esto añadiría desorden y adicional breako returndeclaraciones. Convertir el do/ whileloop en un for(;;)loop sea más consistente en mi humilde opinión. Mi ostracismo hacia esta declaración es similar a mi negativa a usarla strncpy() incluso en los raros casos en los que sería la herramienta adecuada: no permita que los lectores ocasionales se imaginen que estas construcciones son inofensivas, porque en la mayoría de los casos son fuentes de errores difíciles de encontrar. .
chqrlie

@chqrlie al ver la respuesta original era sobre cualquier lenguaje C, supongo que ambas respuestas servirían. C # es mucho más "ahorrador" que sus predecesores, por lo que técnicamente sería más rápido con el do while.
Roy Berris

0

whilelos bucles verifican la condición antes del bucle, los do...whilebucles verifican la condición después del bucle. Esto es útil si desea basar la condición en los efectos secundarios del bucle en ejecución o, como dijeron otros carteles, si desea que el bucle se ejecute al menos una vez.

Entiendo de dónde vienes, pero do-whilees algo que la mayoría usa raramente, y yo nunca lo usé. No lo estás haciendo mal.

No lo estás haciendo mal. Eso es como decir que alguien lo está haciendo mal porque nunca ha usado el byteprimitivo. Simplemente no es tan de uso común.


0

El escenario más común con el que me encuentro donde uso un do/ whileloop es en un pequeño programa de consola que se ejecuta en base a alguna entrada y se repetirá tantas veces como desee el usuario. Obviamente, no tiene sentido que un programa de consola no se ejecute tiempos; pero más allá de la primera vez, depende del usuario, por lo tanto do/ en whilelugar de solo while.

Esto permite al usuario probar un montón de entradas diferentes si lo desea.

do
{
   int input = GetInt("Enter any integer");
   // Do something with input.
}
while (GetBool("Go again?"));

Sospecho que los desarrolladores de software usan do/ whilecada vez menos en estos días, ahora que prácticamente todos los programas bajo el sol tienen una GUI de algún tipo. Tiene más sentido con las aplicaciones de consola, ya que es necesario actualizar continuamente la salida para proporcionar instrucciones o solicitar al usuario información nueva. Con una GUI, por el contrario, el texto que proporciona esa información al usuario puede simplemente sentarse en un formulario y nunca necesitar repetirse mediante programación.


0

Utilizo bucles do-while todo el tiempo cuando leo archivos. Trabajo con muchos archivos de texto que incluyen comentarios en el encabezado:

# some comments
# some more comments
column1 column2
  1.234   5.678
  9.012   3.456
    ...     ...

Usaré un ciclo do-while para leer hasta la línea "column1 column2" para poder buscar la columna de interés. Aquí está el pseudocódigo:

do {
    line = read_line();
} while ( line[0] == '#');
/* parse line */

Luego haré un ciclo while para leer el resto del archivo.


Apoyar los comentarios en cualquier parte del archivo sería trivial (y simplificaría el código en general) si simplemente colocara if (line[0]=='#') continue;justo después de la read_linellamada en su bucle while principal ...
R .. GitHub DETENGA AYUDAR A ICE

No veo cómo implementaría su sugerencia para encontrar un encabezado. (maldición, no puedo averiguar cómo formatear el código en los comentarios, ¡por favor ayuda!) header = false; while (! header) {line = read_line (); si (línea [0] == '#') continuar; encabezado = verdadero; } esto es más claro / simple para usted?
Vuela el

0

Siendo un programador geezer, muchos de mis proyectos de programación escolar usaban interacciones impulsadas por menús de texto. Prácticamente todos usaron algo como la siguiente lógica para el procedimiento principal:

do
    display options
    get choice
    perform action appropriate to choice
while choice is something other than exit

Desde los días escolares, he descubierto que uso el bucle while con más frecuencia.


0

Una de las aplicaciones que he visto está en Oracle cuando miramos conjuntos de resultados.

Una vez que tenga un conjunto de resultados, primero obtenga de él (hacer) y desde ese punto en adelante ... compruebe si la búsqueda devuelve un elemento o no (mientras se encuentra el elemento ...) .. Lo mismo podría aplicarse a cualquier otro " implementaciones similares a fetch.


0

Lo he usado en una función que devolvió la siguiente posición de carácter en una cadena utf-8:

char *next_utf8_character(const char *txt)
{
    if (!txt || *txt == '\0')
        return txt;

    do {
        txt++;
    } while (((signed char) *txt) < 0 && (((unsigned char) *txt) & 0xc0) == 0xc0)

    return (char *)txt;
}

Tenga en cuenta que esta función está escrita desde la mente y no probada. El caso es que, de todos modos, debe realizar el primer paso y debe hacerlo antes de poder evaluar la afección.


Esa es una forma desagradable de escribir *(unsigned char *)txt-0x80U<0x40.
R .. GitHub DEJA DE AYUDAR A ICE

0

Cualquier tipo de entrada de consola funciona bien con do-while porque lo solicita la primera vez y lo vuelve a solicitar cada vez que falla la validación de entrada.


0

Aunque hay muchas respuestas aquí, es mi opinión. Todo se reduce a la optimización. Mostraré dos ejemplos donde uno es más rápido que el otro.

Caso 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);
}

Caso 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));

Entonces, dos harán exactamente las mismas cosas. Pero hay una diferencia fundamental y es que el while requiere una declaración adicional para ingresar el while. Lo cual es feo porque digamos que Guidya se han tomado todos los escenarios posibles de la clase, excepto una variante. Esto significa que tendré que recorrer los 5,316,911,983,139,663,491,615,228,241,121,400,000tiempos. Cada vez que llegue al final de mi estado de cuenta while, tendré que hacer la string.IsNullOrEmpty(fileName)verificación. Así que esto tomaría un poco, una pequeña fracción del trabajo de la CPU. Pero, ¿esta tarea tan pequeña multiplica las posibles combinaciones que tiene la Guidclase y estamos hablando de horas, días, meses o tiempo extra?

Por supuesto, este es un ejemplo extremo porque probablemente no lo vería en producción. Pero si pensamos en el algoritmo de YouTube, es muy posible que se encuentren con la generación de una identificación donde ya se han tomado algunas. Entonces se trata de grandes proyectos y optimización.


0

Me gusta entender estos dos como:
while-> 'repetir hasta',
do ... while-> 'repetir si'.


-1

Me encontré con esto mientras investigaba el bucle adecuado para usar en una situación que tengo. Creo que esto satisfará completamente una situación común en la que un bucle do .. while es una mejor implementación que un bucle while (lenguaje C #, ya que indicó que es el principal para el trabajo).

Estoy generando una lista de cadenas basada en los resultados de una consulta SQL. El objeto devuelto por mi consulta es un SQLDataReader. Este objeto tiene una función llamada Read () que avanza el objeto a la siguiente fila de datos y devuelve verdadero si había otra fila. Devolverá falso si no hay otra fila.

Con esta información, quiero devolver cada fila a una lista y luego detenerme cuando no haya más datos para devolver. Un bucle Do ... While funciona mejor en esta situación, ya que garantiza que se agregará un elemento a la lista ANTES de verificar si hay otra fila. La razón por la que esto se debe hacer ANTES de verificar el while (condición) es que cuando verifica, también avanza. El uso de un bucle while en esta situación haría que se saltara la primera fila debido a la naturaleza de esa función en particular.

En breve:

Esto no funcionará en mi situación.

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

   return list;

Esta voluntad.

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

    return list;

El uso de SQLDataReader sería bucles anidados. El interno llama Read()y debe ser un bucle while, ya que la primera Read()llamada accede a la primera fila. El externo llama NextResult()y debería ser un do-while, porque el primer conjunto de datos de resultados está activo antes de la primera NextResult()llamada. Los fragmentos de código no tienen mucho sentido, especialmente porque los comentarios no coinciden con el código y son incorrectos.
Ben Voigt

-1
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;

Debe responder su propia pregunta como si fuera a responder a la de otra persona. Incluye una explicación y un código
Simon
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.