'fazer ... enquanto' vs. 'enquanto'


86

Possíveis duplicatas:
While vs. Do While
Quando devo usar do-while em vez de while loops?

Eu tenho programado há um tempo (2 anos de trabalho + 4,5 anos de graduação + 1 ano de pré-faculdade), e nunca usei um loop do-while que não seja forçado no curso de Introdução à Programação. Tenho uma sensação crescente de que estou programando errado se nunca encontrar algo tão fundamental.

Será que simplesmente não encontrei as circunstâncias corretas?

Quais são alguns exemplos em que seria necessário usar um do-while em vez de um while?

(Minha formação foi quase toda em C / C ++ e meu trabalho é em C #, portanto, se houver outra linguagem em que absolutamente faça sentido porque o fazer enquanto funciona de maneira diferente, essas questões não se aplicam realmente.)

Para esclarecer ... eu sei a diferença entre a whilee a do-while. Enquanto verifica a condição de saída e, em seguida, executa as tarefas. do-whileexecuta tarefas e verifica a condição de saída.


42
Pelo que vale a pena, após uma década de programação como minha carreira, usei um loop do-while uma ou duas vezes.
Matt Greer

@Matt - Isso me faz sentir melhor. Pelo menos significa que não estou sozinho.
mphair

2
Vou apoiar Matt e adicionar mais uma década ou mais a isso. Eu raramente uso o loop do-while também.
quentin-starin

MUITAS duplicatas. Aqui está um link para
vários

3
A “pergunta principal” correta parece ser stackoverflow.com/questions/224059/…
Donal Fellows

Respostas:


115

Se você sempre deseja que o loop seja executado pelo menos uma vez. Não é comum, mas eu uso de vez em quando. Um caso em que você pode querer usá-lo é tentar acessar um recurso que pode exigir uma nova tentativa, por exemplo

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

} while (user says retry);

3
Portanto, acho que isso seguiria em "Não me deparei com essa circunstância."
mphair

7
honestamente, eu muito raramente me deparo com uma circunstância em que eu só preciso usar um do ... enquanto ...
Stan R.

1
Talvez um pouco curto, mas Bob está correto. Do / while deve ser usado quando você deseja executar o bloco de código pelo menos uma vez . Você deve usar um loop while quando não souber se deseja executá-lo uma única vez. Dito isso, posso dizer que, com cerca de 15 anos de experiência em desenvolvimento, usei muitas vezes mais loops while do que loops do / while.
ConsultUtah

1
Eu também os usei de vez em quando, embora raramente. Depois de um tempo, eles geralmente são refatorados em um loop while normal - só porque as áreas ao redor mudaram e deram certo ... ainda mais desajeitados do que antes.
Joshua

2
É bastante comum. Mas não vejo por que em seu exemplo você não usaria um loop while. E não vejo por que essa resposta está sendo votada a favor.

65

do-while é melhor se o compilador não for competente em otimização. do-while tem apenas um único salto condicional, ao contrário de for e while que têm um salto condicional e um salto incondicional. Para CPUs que têm pipeline e não fazem previsão de branch, isso pode fazer uma grande diferença no desempenho de um loop fechado.

Além disso, como a maioria dos compiladores é inteligente o suficiente para realizar essa otimização, todos os loops encontrados no código descompilado normalmente serão do-while (se o descompilador ao menos se preocupar em reconstruir loops a partir de gotos locais anteriores).


5
+1 para adicionar informações técnicas relevantes à escolha entre as formas de loop.
quentin-starin

2
Não apenas prematuro, mas inútil. Se você realmente queria um loop while, ou seja, a capacidade de iterar 0 vezes, você deve colocar o loop em um if que trará esse salto de volta.
JeremyP

3
@Jeremy: O salto de que você fala está fora do loop, não é executado N vezes.
Ben Voigt

1
Considere também o uso clássico de do-while no dispositivo de Duff (em que um loop while é transformado em um do-while desenrolado com uma etapa maior mais uma tabela de salto para lidar com o restante), que reduz drasticamente a sobrecarga do loop - em aplicativos como memset, memcmp, memcpy pode aumentar o rendimento por um fator de 10.
Ben Voigt

@BenVoigt Sei que seu comentário já tem uma década, mas o Dispositivo de Duff não deve ser mencionado sem a advertência muito importante - ele se tornou menos eficiente em compiladores modernos, porque os compiladores modernos geralmente podem desenrolar de forma inteligente loops diretos como ideais para a máquina-alvo , embora geralmente não tenham lógica para descobrir a intenção de um dispositivo de Duff e, portanto, não podem otimizá-lo tão bem. O que é uma grande lição sobre como otimizar o código para alguma máquina-alvo em vez de um "otimizador suficientemente avançado" abstrato.
mtraceur

12

Eu usei isso em uma função TryDeleteDirectory. Era algo assim

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

Agradável. Este é o primeiro exemplo que realmente faz sentido ser embrulhado em um do ... while.
Joshua

4
Por que / como isso é melhor do que um padrão while?
Josh Stodola

O loop sempre será executado uma vez, então você pode querer fazer algo e tentar novamente se falhar. Se você usar um loop while normal, verificará se ele falha antes mesmo de fazê-lo na primeira iteração.
NibblyPig

1
@SLC Mas você não gostaria de verificar se o diretório existe de antemão?
Josh Stodola

1
@Josh Neste exemplo, sim. Mas se você estivesse tentando abrir uma conexão com um servidor ocupado, você se conectaria primeiro e veria se a resposta era 'ocupado'. Se fosse, você tentaria novamente algumas vezes antes de desistir.
NibblyPig

11

Faça while é útil quando você deseja executar algo pelo menos uma vez. Como um bom exemplo para usar do while vs. while, digamos que você queira fazer o seguinte: Uma calculadora.

Você poderia abordar isso usando um loop e verificando após cada cálculo se a pessoa deseja sair do programa. Agora você provavelmente pode presumir que, uma vez que o programa seja aberto, a pessoa deseja fazer isso pelo menos uma vez, então você pode fazer o seguinte:

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

2
Na verdade, agora que você mencionou, qualquer tipo de interface de menu baseada em console funcionaria bem em um loop do ... while também. Por exemplo, solicitar opções (uma tecla por vez) e apenas sair quando escolher continuar ou sair.
Joshua

7
continueé uma palavra-chave; D
Thomas Eding

Atrinithis: Lol ... eu escorreguei. Obrigado por me corrigir lá.

== trueNão é necessário. cont == truese cont for verdadeiro, retorna verdadeiro. Isso é totalmente inútil.
Mr.DeleteMyMessages

11

Essa é uma resposta meio indireta, mas essa pergunta me fez pensar sobre a lógica por trás dela e pensei que valeria a pena compartilhar isso.

Como todo mundo já disse, você usa um do ... whileloop quando deseja executar o corpo pelo menos uma vez. Mas em que circunstâncias você gostaria de fazer isso?

Bem, a classe de situações mais óbvia que posso pensar seria quando o valor inicial ("não ativado") da condição de verificação é o mesmo de quando você deseja sair . Isso significa que você precisa executar o corpo do loop uma vez para preparar a condição para um valor não existente e, em seguida, executar a repetição real com base nessa condição. Com os programadores sendo tão preguiçosos, alguém decidiu encerrar isso em uma estrutura de controle.

Portanto, por exemplo, a leitura de caracteres de uma porta serial com um tempo limite pode assumir a forma (em 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)

Observe a duplicação do código: char_read = port.read(1) . Se Python tivesse um do ... whileloop, eu poderia ter usado:

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

O benefício adicional para idiomas que criam um novo escopo para loops: char_read não polui o namespace da função. Mas observe também que há uma maneira melhor de fazer isso, e é usando o Nonevalor do Python :

response_buffer = []
char_read = None

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

response = ''.join(response_buffer)

Portanto, aqui está o ponto crucial do meu ponto: em linguagens com tipos anuláveis, a situação initial_value == exit_value surge muito menos freqüência, e que pode ser por isso que você não encontrá-lo. Não estou dizendo que isso nunca aconteça, porque ainda há momentos em que uma função retornará Nonepara significar uma condição válida. Mas, na minha opinião apressada e brevemente considerada, isso aconteceria muito mais se as linguagens que você usou não permitissem um valor que significa: esta variável ainda não foi inicializada.

Este não é um raciocínio perfeito: na realidade, agora que os valores nulos são comuns, eles simplesmente formam mais um elemento do conjunto de valores válidos que uma variável pode assumir. Mas, na prática, os programadores têm uma maneira de distinguir entre uma variável estar em estado sensível, que pode incluir o estado de saída do loop, e ela estar em um estado não inicializado.


Esta é uma das respostas mais interessantes que li aqui. Boa contribuição.
Bob Moore

As duas versões não são equivalentes. Se a primeira leitura retornar None, a whileversão corretamente não adiciona nada ao buffer de resposta, mas sua doversão sempre adiciona algo.
David Stone

@DavidStone read()não deve retornar nunca None. Se você estiver usando uma biblioteca onde existe, a premissa não se aplica (ou seja, que o valor sentinela não está no conjunto de valores de verificação possíveis).
detly

Com sua última edição, vejo o que deveria ter dito em ''vez de None. Algum tipo de valor que avalia como falso. Atribui isso à minha falta de familiaridade com a readfunção do Python .
David Stone

@DavidStone Eu não entendo. Se read()retornar '', nada será acrescentado à string, ela está vazia.
detly

7

Eu os usei bastante quando estava na escola, mas não tanto desde então.

Em teoria, eles são úteis quando você deseja que o corpo do loop seja executado uma vez antes da verificação da condição de saída. O problema é que, para os poucos casos em que não desejo a verificação primeiro, normalmente desejo a verificação de saída no meio do corpo do loop, e não no final. Nesse caso, prefiro usar o conhecido for (;;)com um if (condition) exit;lugar no corpo.

Na verdade, se estou um pouco instável na condição de saída do loop, às vezes acho útil começar a escrever o loop como um for (;;) {}com uma instrução de saída quando necessário e, então, quando terminar, posso ver se pode ser " limpo "movendo as inicializações, condições de saída e / ou código de incremento dentro fordos parênteses de.


5
Por curiosidade ... por que "for (;;)" em vez de "while (true)"?
mphair

4
Provavelmente apenas experimente. Passei a me igualar for(;;)a "loop infinito", while(true)mas preciso parar e pensar a respeito. Talvez seja porque eu estava codificando C antes de haver um true. Antigamente tínhamos apenas TRUEuma macro, e se algo estivesse com erros, eu teria que ir me convencer de que a macro não foi redefinida de 0alguma forma (aconteceu!). Com for(;;)não há chance disso. Se você insiste na forma while, eu quase prefiro ver while (1). É claro que alguns podem se perguntar se não é a letra l ...
TED

1
@mphair: Sim, se você tomar nota do texto que o editor insere quando você coloca o texto em itálico ou codeifytexto, pode simplesmente digitá-lo diretamente no campo de comentários. Já vi algumas pessoas colocarem hiperlinks, mas isso é um pouco pesado demais para mim.
TED

2
@TED: Minha notação preferida para loop-until-explicit-exit é "do {} while (1);". A propósito, no trabalho de sistemas embarcados, meu paradigma de loop normal é "i = 10; do {} while (- i);". Para loops apertados, isso é muito mais rápido do que um for () típico; Eu acho que é mais legível usar isso consistentemente como o padrão de loop quando uma contagem de aumento não é necessária do que usar for () arbitrariamente em casos de desempenho não crítico.
supercat

2
Somando-se ao while (1) e para (;;) desusão, eu vi código usando para (EVER) com EVER definido como ;;
asr

6

Uma situação em que você sempre precisa executar um trecho de código uma vez e, dependendo do resultado, possivelmente mais vezes. O mesmo pode ser produzido com um whileloop regular também.

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

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

6

do whileé se você deseja executar o bloco de código pelo menos uma vez. whilepor outro lado, nem sempre será executado dependendo dos critérios especificados.


5

É simples assim:

pré-condição vs pós-condição

  • while (cond) {...} - pré-condição, executa o código somente após verificação.
  • do {...} while (cond) - pós-condição, o código é executado pelo menos uma vez.

Agora que você conhece o segredo .. use-os com sabedoria :)


1
Como eu disse, eu sei como eles funcionam, só não tenho certeza de que caso um faz sentido sobre o outro.
mphair

É lógico que você use o do {} while quando tiver certeza de que terá que passar pelo menos uma vez no loop. Como, por exemplo, se você tem uma função que encontra um elemento em um array e você já colocou um array if.IsEmpty () then return; . Se passou nessa verificação, você pode usar do {} while. do-while também é fácil de pensar, como um loop repetitivo: "Eu como até ficar satisfeito" se traduz em do {comer ();} while (! satisfeito ();). Testar a condição antes do loop é considerado mais seguro ... e é por isso que é usado com mais frequência.
Ioan Paul Pirau

4

Vejo que essa pergunta foi respondida adequadamente, mas gostaria de adicionar este cenário de caso de uso muito específico. Você pode começar a usar do ... enquanto com mais freqüência.

do
{
   ...
} while (0)

é freqüentemente usado para #defines multilinhas. Por exemplo:

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

Isso funciona bem para:

r = 4;
h = 3;
compute_values;

-mas- há uma pegadinha para:

if (shape == circle)  compute_values;

conforme isso se expande para:

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

Se você envolvê-lo em um loop do ... while (0), ele se expande corretamente para um único bloco:

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

2

As respostas até agora resumem o uso geral do do-while. Mas o OP pediu um exemplo, então aqui está um: Obtenha a entrada do usuário. Mas a entrada do usuário pode ser inválida - então você pede uma entrada, valida-a, prossiga se for válida, caso contrário, repita.

Com do-while, você obtém a entrada enquanto a entrada não é válida. Com um loop while regular, você obtém a entrada uma vez, mas se for inválida, você a obterá novamente e novamente até que seja válida. Não é difícil perceber que o primeiro é mais curto, mais elegante e mais simples de manter se o corpo da alça ficar mais complexo.


Acho que nunca os usei para isso porque geralmente acabo dizendo ao usuário o que há de errado com sua entrada. O que significa que o condicional estaria no centro de um loop e eu apenas breakse a entrada estiver correta.
mphair

@mphair: Na verdade, para esse tipo de situação, às vezes posso estar mais inclinado a usar um "do {} while (0);" loop, usando "continue;" se a entrada do usuário for inaceitável. Se houver apenas um problema e mensagem, usando "do {} while (1);" e "quebrar;" funciona bem, mas se houver vários motivos para exigir a reentrada, o botão "continue;" construir funciona mais bem.
supercat

2

Eu o usei para um leitor que lê a mesma estrutura várias vezes.

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

1

Usei um do whilequando estou lendo um valor de sentinela no início de um arquivo, mas fora isso, não acho anormal que essa estrutura não seja muito usada - do-whiles são realmente situacionais.

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

Aqui está minha teoria de por que a maioria das pessoas (inclusive eu) preferem os loops while () {} para fazer {} while (): Um loop while () {} pode ser facilmente adaptado para funcionar como um loop do..while () enquanto o oposto não é verdade. Um loop while é de certa forma "mais geral". Os programadores também gostam de padrões fáceis de entender. Um loop while diz logo no início qual é o seu invariante e isso é uma coisa boa.

Aqui está o que quero dizer sobre a coisa "mais geral". Faça este loop do..while:

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

Transformar isso em um loop while é simples:

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

Agora, pegamos um modelo de loop while:

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

E transformar isso em um loop do..while, produz esta monstruosidade:

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

 } while(INV)
}

Agora temos duas verificações em extremidades opostas e se a invariante muda, você deve atualizá-la em dois lugares. De certa forma, faça .. enquanto é como as chaves de fenda especializadas na caixa de ferramentas que você nunca usa, porque a chave de fenda padrão faz tudo o que você precisa.


1
Substituindo um "do {} while (x);" loop em um "while (x);" loop requer que X seja uma condição que pode ser facilmente "preparada" ou que seja "naturalmente" verdadeira na primeira passagem. Para mim, instruções priming antes de um loop implicam que algo dentro do loop precisa de priming, e um loop while (x) {}; "implica que o loop pode ser executado zero vezes. Se eu quiser um loop que será executado pelo menos uma vez, eu use um loop "do {} while (x);"
supercat

1

Estou programando há cerca de 12 anos e apenas 3 meses atrás encontrei uma situação em que era realmente conveniente usar do-while, pois uma iteração era sempre necessária antes de verificar uma condição. Portanto, acho que seu grande momento está à frente :).


1
Quase todas as vezes que vi um fazer ... embora fosse por causa de uma falta de compreensão do problema e envolvesse algum hack terrível. Existem exceções, mas de modo geral, se você quiser ... enquanto, você deve repensar o que está fazendo ... :-)
Brian Knoblauch

2
Se você estivesse certo, então do-while seria excluído de todas as linguagens de programação para não confundir os programadores :).
Narek

@Narek: Já se passaram mais de sete anos desde que você escreveu isso. Você teve mais circunstâncias em que do whilehavia uma solução melhor sem arrependimentos?
chqrlie

Sim, provavelmente mais uma vez: D
Narek

1

Não consigo imaginar como você passou tanto tempo sem usar um do...whileloop.

Há um em outro monitor agora e vários desses loops nesse programa. Eles são todos na forma:

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

1

É uma estrutura bastante comum em um 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

o REPEAT UNTIL(cond)ser umdo {...} while(!cond)

Às vezes, a espera pelo trabalho (0) pode ser mais barata em termos de CPU (mesmo eliminar o cálculo do tempo limite pode ser uma melhoria com taxas de chegada muito altas). Além disso, existem muitos resultados da teoria das filas que tornam o número atendido em um período de grande movimento uma estatística importante. (Veja por exemplo Kleinrock - Vol 1.)

Similarmente:

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

onde check for and do other workpode ser exorbitantemente caro para colocar no loop principal ou talvez um kernel que não suporte um eficientewaitany(waitcontrol*,n) operação de tipo ou talvez uma situação onde uma fila priorizada pode privar o outro trabalho e o acelerador é usado como controle de fome.

Esse tipo de balanceamento pode parecer um hack, mas pode ser necessário. O uso cego de conjuntos de encadeamentos anularia inteiramente os benefícios de desempenho do uso de um encadeamento de zelador com uma fila privada para uma estrutura de dados complicada de alta taxa de atualização, pois o uso de um conjunto de encadeamentos em vez de um encadeamento de zelador exigiria uma implementação segura de encadeamento.

Eu realmente não quero entrar em um debate sobre o pseudocódigo (por exemplo, se o desligamento solicitado deve ser testado no UNTIL) ou threads de zelador versus pools de threads - isso serve apenas para dar uma ideia de um caso de uso específico de a estrutura do fluxo de controle.


1

Esta é minha opinião pessoal, mas esta questão implora por uma resposta enraizada na experiência:

  • Eu tenho programado em C por 38 anos, e nunca uso do/ whileloops em código normal.

  • O único uso convincente para esta construção é em macros, onde pode envolver várias instruções em uma única instrução por meio de um do { multiple statements } while (0)

  • Já vi inúmeros exemplos de do/ whileloops com detecção de erro falsa ou chamadas de função redundantes.

  • Minha explicação para essa observação é que os programadores tendem a modelar problemas incorretamente quando pensam em termos de do/ whileloops. Eles perdem uma condição final importante ou perdem a possível falha da condição inicial que eles movem para o final.

Por essas razões, eu acredito que onde há umdowhile loop / , há um bug , e regularmente desafio os programadores novatos a me mostrarem um do/while loop onde não consigo identificar um bug nas proximidades.

Este tipo de loop pode ser facilmente evitado: use ae for (;;) { ... }adicione os testes de terminação necessários onde forem apropriados. É bastante comum que haja mais de um teste desse tipo.

Aqui está um exemplo clássico:

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

Isso falhará se o arquivo não terminar com uma nova linha. Um exemplo trivial de tal arquivo é o arquivo vazio.

Uma versão melhor é esta:

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

Como alternativa, esta versão também oculta a cvariável:

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

Tente pesquisar por while (c != '\n'); em qualquer mecanismo de pesquisa e você encontrará bugs como este (recuperado em 24 de junho de 2017):

Em ftp://ftp.dante.de/tex-archive/biblio/tib/src/streams.c , função getword(stream,p,ignore), tem um do/ whilee com certeza pelo menos 2 bugs:

  • c é definido como um char e
  • há um loop infinito potencial while (c!='\n') c=getc(stream);

Conclusão: evite do/ whileloops e procure por bugs quando encontrar um.


1
Eu prefiro evitar while() {}loops, porque eles são mais seguros em termos de verificações iniciais, então tendem a deixá-lo "louco", preguiçoso para pensar em um algoritmo melhor, colocar uma tonelada de checagem de erros desnecessária, etc. "Falta de do{}while()uso" é um sinal de mau (sem cérebro) ou de um programador novato, produz um código de qualidade inferior e mais lento. Então eu primeiro me pergunto "É estritamente um caso while () {}?" Se não - eu apenas tentarei escrever do while loop, apesar de poder exigir mais raciocínio e precisão dos dados de entrada
xakepp35

Eu entendo sua resposta, mas posso pensar em alguns cenários possíveis em que isso seria realmente melhor. Observe while: prnt.sc/v2zy04 ou at do while: prnt.sc/v2zyka . Não sou programador há tanto tempo quanto você, mas não consegui encontrar um bug aí. É bastante claro que o do while é mais limpo porque não requer a verificação extra do while para entrar no loop. Se estamos falando sobre otimização de código, então eu diria que é muito claro.
Roy Berris

@RoyBerris: seu exemplo é interessante. Em um programa C, as funções usadas dentro do loop exigiriam testes extras para garantir que não falharam. Isso adicionaria desordem extra e breakou returninstruções. Transformar o loop do/ whileem um for(;;)loop IMHO mais consistente. Meu ostracismo em relação a essa afirmação é semelhante à minha recusa em usar, strncpy() mesmo nos raros casos em que seria a ferramenta certa: não deixe leitores casuais imaginarem que essas construções são inofensivas, porque na maioria dos casos são fontes de insetos difíceis de encontrar .
chqrlie

@chqrlie vendo que a resposta original era sobre qualquer linguagem C, acho que ambas as respostas serviriam. C # é muito mais "econômico" do que seus predecessores, então seria tecnicamente mais rápido com o uso do while.
Roy Berris

0

whileos loops verificam a condição antes do loop, os do...whileloops verificam a condição após o loop. Isso é útil se você quiser basear a condição nos efeitos colaterais do loop em execução ou, como outros usuários disseram, se quiser que o loop seja executado pelo menos uma vez.

Eu entendo de onde você vem, mas do-whileé algo que raramente uso, e eu nunca usei. Você não está fazendo errado.

Você não está fazendo errado. É como dizer que alguém está fazendo errado porque nunca usou o byteprimitivo. Só não é tão comumente usado.


0

O cenário mais comum que encontro em que uso um loop do/ whileé em um pequeno programa de console que é executado com base em alguma entrada e se repetirá quantas vezes o usuário quiser. Obviamente, não faz sentido que um programa de console nunca seja executado; mas além da primeira vez, depende do usuário - portanto, do/ em whilevez de apenas while.

Isso permite que o usuário experimente várias entradas diferentes, se desejar.

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

Suspeito que os desenvolvedores de software usam do/ whilecada vez menos hoje em dia, agora que praticamente todo programa sob o sol tem algum tipo de interface gráfica do usuário. Faz mais sentido com aplicativos de console, pois há uma necessidade de atualizar continuamente a saída para fornecer instruções ou solicitar ao usuário novas informações. Com uma GUI, em contraste, o texto que fornece essas informações ao usuário pode apenas ficar em um formulário e nunca precisa ser repetido programaticamente.


0

Eu uso loops do-while o tempo todo ao ler arquivos. Eu trabalho com muitos arquivos de texto que incluem comentários no cabeçalho:

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

Vou usar um loop do-while para ler até a linha "coluna1 coluna2" para que eu possa procurar a coluna de interesse. Este é o pseudocódigo:

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

Em seguida, farei um loop while para ler o resto do arquivo.


Suportar comentários em qualquer parte do arquivo seria trivial (e simplificaria o código geral) se você apenas colocasse if (line[0]=='#') continue;logo após a read_linechamada em seu loop while principal ...
R .. GitHub PARAR DE AJUDAR ICE

Não vejo como implementaria sua sugestão para encontrar um cabeçalho. (droga, não consigo descobrir como formatar o código nos comentários, por favor, ajude!) header = false; while (! cabeçalho) {line = read_line (); if (linha [0] == '#') continue; cabeçalho = verdadeiro; } isso é mais claro / simples para você?
voa em

0

Sendo um programador geezer, muitos dos meus projetos de programação escolar usaram interações dirigidas por menu de texto. Praticamente todos usaram algo como a seguinte lógica para o procedimento principal:

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

Desde os tempos de escola, descobri que uso o loop while com mais frequência.


0

Um dos aplicativos que vi é no Oracle, quando olhamos os conjuntos de resultados.

Depois de ter um conjunto de resultados, primeiro você busca a partir dele (faz) e a partir desse ponto .. verifique se a busca retorna um elemento ou não (enquanto o elemento for encontrado ..) .. O mesmo pode ser aplicável a qualquer outro " implementações semelhantes a busca ".


0

Eu o usei em uma função que retornou a próxima posição do caractere em uma string 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;
}

Observe que esta função foi escrita da mente e não foi testada. O ponto é que você tem que dar o primeiro passo de qualquer maneira e tem que fazer antes de poder avaliar a condição.


É uma forma desagradável de escrever *(unsigned char *)txt-0x80U<0x40.
R .. GitHub PARAR DE AJUDAR O GELO

0

Qualquer tipo de entrada de console funciona bem com do-while porque você pergunta na primeira vez e faz a solicitação novamente sempre que a validação de entrada falha.


0

Mesmo que haja muitas respostas, aqui está a minha opinião. Tudo se resume à otimização. Vou mostrar dois exemplos em que um é mais rápido que o outro.

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

Portanto, dois farão exatamente as mesmas coisas. Mas há uma diferença fundamental: o while requer uma instrução extra para inserir o while. O que é feio, porque digamos que todos os cenários possíveis da Guidclasse já foram escolhidos, exceto por uma variante. Isso significa que terei que dar uma volta por 5,316,911,983,139,663,491,615,228,241,121,400,000cima. Toda vez que eu chegar ao final do meu extrato while, terei de fazer a string.IsNullOrEmpty(fileName)verificação. Portanto, isso ocuparia um pouco, uma pequena fração do trabalho da CPU. Mas faça esta tarefa muito pequena vezes as combinações possíveis doGuid turma tem e estamos falando de horas, dias, meses ou horas extras?

Claro que este é um exemplo extremo porque você provavelmente não veria isso na produção. Mas se pensarmos no algoritmo do YouTube, é bem possível que eles encontrem a geração de um ID onde alguns IDs já foram obtidos. Portanto, tudo se resume a grandes projetos e otimização.


0

Eu gosto de entender esses dois como:
while-> 'repetir até',
do ... while-> 'repetir se'.


-1

Eu encontrei isso enquanto pesquisava o loop adequado para usar em uma situação que tenho. Acredito que isso irá satisfazer totalmente uma situação comum em que um loop do .. while é uma implementação melhor do que um loop while (linguagem C #, já que você declarou que é o seu principal para o trabalho).

Estou gerando uma lista de strings com base nos resultados de uma consulta SQL. O objeto retornado por minha consulta é um SQLDataReader. Este objeto tem uma função chamada Read () que avança o objeto para a próxima linha de dados e retorna true se houver outra linha. Ele retornará falso se não houver outra linha.

Usando essas informações, quero retornar cada linha a uma lista e, em seguida, parar quando não houver mais dados para retornar. Um loop Do ... While funciona melhor nesta situação, pois garante que a adição de um item à lista acontecerá ANTES de verificar se há outra linha. A razão pela qual isso deve ser feito ANTES de verificar o while (condição) é que quando ele verifica, ele também avança. O uso de um loop while nesta situação faria com que ele ignorasse a primeira linha devido à natureza dessa função específica.

Em resumo:

Isso não funcionará na minha situação.

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

   return list;

Isso vai.

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

    return list;

O uso de SQLDataReader seria loops aninhados. O interno chama Read()e deve ser um loop while, já que a primeira Read()chamada acessa a primeira linha. O externo chama NextResult()e deve ser um do-while, porque o primeiro conjunto de dados de resultado está ativo antes da primeira NextResult()chamada. Os snippets de código não fazem muito sentido, especialmente porque os comentários não correspondem ao código e estão errados.
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;

Você deve responder à sua própria pergunta como se fosse responder à de outra pessoa. Incluiu uma explicação, bem como o código
Simon
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.