Menu

while e do while em C#: sintaxe, leitura de entrada e armadilhas

Como os laços while e do while funcionam em C#: a condição verificada antes ou depois do corpo, ler a entrada até um valor sentinela ou até o fim, while (true) com break, e os erros de laço infinito que pegam muita gente.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

Um laço while repete o corpo enquanto uma condição continuar verdadeira. Use-o quando você não sabe de antemão quantas iterações vai precisar: continuar até um saldo atingir uma meta, uma fila ficar vazia ou a entrada acabar.

Saída:

Year 1: 1070.00
Year 2: 1144.90
Year 3: 1225.04
Year 4: 1310.80
Year 5: 1402.55
Year 6: 1500.73
Goal reached after 6 years

A condição é verificada antes de cada iteração, inclusive a primeira. Se savings já tivesse atingido a meta, o corpo nunca executaria e o programa imprimiria "after 0 years". O laço depende de o corpo mudar algo que a condição lê; aqui savings cresce a cada ano até savings < goal ficar falso.

do while: executa pelo menos uma vez

Um laço do while move o teste para o fim, então o corpo sempre executa pelo menos uma vez:

Saída:

Attempt 1: got 7
Attempt 2: got 4
Attempt 3: got 1
Done after 3 attempts

O primeiro valor de code só existe depois que o corpo executou uma vez, que é exatamente quando um do while se encaixa. Dois detalhes de sintaxe pegam muita gente:

  • O ponto e vírgula depois de while (code != 1) é obrigatório. Esquecê-lo é um erro de compilação.
  • As variáveis usadas na condição precisam ser declaradas antes do do. Uma variável declarada dentro das chaves está fora de escopo quando a condição executa, então do { int code = ...; } while (code != 1); não compila.

O mesmo laço escrito com while precisa de uma primeira chamada duplicada antes do laço ou de um valor inicial fictício que force a primeira passada. O do while expressa diretamente "tente e depois decida se vai tentar de novo".

Lendo a entrada até um sentinela

Ler linhas até uma palavra de parada, ou até a entrada acabar, é o laço while clássico de livro. Console.ReadLine() retorna null quando não há mais entrada, então teste as duas coisas:

Saída:

skipping "abc": not a number
3 amounts, total 49.50

(line = Console.ReadLine()) != null atribui a próxima linha e a testa em uma única expressão; os parênteses em volta da atribuição são obrigatórios porque != tem precedência maior que =. O laço para em done, então o 99 depois dele nunca é lido. decimal.TryParse rejeita abc sem lançar exceção, e continue pula para a próxima linha. Sem a verificação de null, chegar ao fim da entrada passaria null para TryParse para sempre, já que ReadLine continua retornando null.

Um do while combina com o padrão de pedir e validar, em que a pergunta precisa aparecer pelo menos uma vez:

Saída:

Enter your age:
"-4" is not a valid age
Enter your age:
"fifteen" is not a valid age
Enter your age:
Age accepted: 15

A pergunta está dentro do laço, então ela se repete depois de cada resposta rejeitada, e age é declarada antes do do para que o código depois do laço possa usá-la. Com um usuário no teclado, cada resposta aparece no console depois da pergunta; com a entrada redirecionada, como aqui, só a saída do próprio programa é mostrada.

while (true) com break

Às vezes o ponto natural de saída fica no meio do corpo, depois de parte do trabalho e antes do resto. Escreva o laço como while (true) e saia com break:

Saída:

processing: resize photo
processing: send email
stop signal received
1 job(s) left in the queue

Dequeue tira o próximo trabalho da frente da fila, e o laço sai assim que vê o marcador de parada, então o último trabalho fica na fila. while (true) não é um mau sinal quando a saída é clara e fica perto do começo do corpo. Passa a ser quando há vários break espalhados por um corpo longo; aí uma condição bool com nome ou um método com return é mais fácil de acompanhar. A página de break e continue mostra como sair de laços aninhados.

Laços que nunca terminam

Um laço infinito sem querer tem uma de três causas.

O corpo nunca muda a condição. O contador nunca é incrementado, ou a variável errada é:

int i = 0;
while (i < 5)
{
    Console.WriteLine(i);   // i++ forgotten: prints 0 forever
}

Um ponto e vírgula depois da condição. O ponto e vírgula é o corpo inteiro do laço, e o bloco abaixo dele executa depois do laço (que nunca termina):

while (retries < 3);        // warning CS0642: Possible mistaken empty statement
{
    retries++;
}

Uma condição que passa do alvo. Testar != quando a variável anda em passos pode pular o valor de parada. while (x != 10) x += 3; vai 0, 3, 6, 9, 12 e passa direto do 10 (só cai no 10 por acaso, depois que o int estoura e dá a volta bilhões de passos depois). Teste com < ou > em vez de != sempre que o passo não for 1. O mesmo vale para valores double, que raramente acertam um alvo exato: while (x != 1.0) x += 0.1; nunca termina.

Escolhendo entre while, do while e for

SituaçãoLaço
Número de iterações conhecido, ou um índicefor
Cada elemento de uma coleçãoforeach
Repetir enquanto uma condição vale, possivelmente zero vezeswhile
O corpo precisa executar uma vez antes de a condição fazer sentidodo while
Teste de saída no meio do corpowhile (true) com break

Qualquer laço for pode ser reescrito como um laço while e vice-versa; a escolha é sobre qual deles coloca a lógica do laço onde o leitor espera. Quando o contador, o teste e o passo existem, o for os mantém em uma linha. Quando o laço é guiado por um estado que muda dentro do corpo, o while deixa isso claro.

Perguntas frequentes

Qual a diferença entre while e do while em C#?

Um laço while verifica a condição antes de cada iteração, então o corpo pode executar zero vezes. Um laço do { } while (condition); verifica depois de cada iteração, então o corpo sempre executa pelo menos uma vez. Use do while quando a primeira passada produz o valor que a condição testa, como ler uma entrada e depois validá-la.

Qual é a sintaxe de um laço do while em C#?

do { body } while (condition);. Repare no ponto e vírgula depois do parêntese de fechamento: ele é obrigatório, e esquecê-lo é um erro de compilação. A condição pode usar variáveis atribuídas no corpo, mas elas precisam ser declaradas antes do do, porque as chaves do corpo são um escopo separado.

Como escrever while (true) em C#?

while (true) { ... } repete para sempre até que algo dentro dele saia com break, return ou uma exceção. É a forma natural quando o teste de saída fica no meio do corpo, como ler uma linha e parar quando ela estiver vazia.

Como ler a entrada até o usuário digitar uma palavra ou a entrada acabar em C#?

Faça o laço sobre Console.ReadLine(), que retorna null no fim da entrada: string line; while ((line = Console.ReadLine()) != null && line != "done") { ... }. A atribuição dentro da condição lê a próxima linha e a testa em um só passo.

Por que meu laço while em C# nunca termina?

Normalmente o corpo nunca muda o que a condição testa (um i++ esquecido), ou há um ponto e vírgula logo depois da condição: while (count < 10); é um laço com corpo vazio que gira para sempre. O compilador avisa sobre o segundo caso com CS0642, Possible mistaken empty statement.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR