Os Laços While e Do-While: Um Guia Visual e Prático
Aprenda os laços while e do-while de forma visual: como verificam antes ou depois, os três ingredientes de todo laço, validação de entrada, sentinelas, break e continue, armadilhas de laço infinito, exemplos reais divertidos (dobrar papel, Collatz) e exercícios.

Nesta página
Computadores nunca ficam entediados. Peça para um deles fazer algo um milhão de vezes e ele faz, sem reclamar. Os laços (ou loops) são o jeito de pedir. Este artigo trata dos dois laços feitos para "continue até algo acontecer": o laço while ("enquanto") e o seu irmão, o laço do-while ("faça… enquanto").
Você vai ver como eles funcionam passo a passo, dobrar uma folha de papel até a Lua, perseguir um número que pula como granizo, montar um jogo e um menu e aprender a reconhecer o laço infinito antes que ele trave o seu programa. Exercícios com respostas fecham o artigo.
Os exemplos estão em C++, mas while e do-while são quase iguais em C, Java, C#, JavaScript e muitas outras linguagens.
while vs. do-while num relance
Os dois laços repetem um bloco de código enquanto uma condição continuar verdadeira. A única diferença é quando eles a verificam:

while (condicao) {
// roda de novo e de novo, enquanto a condição for verdadeira
}do {
// roda uma vez primeiro, depois de novo enquanto a condição for verdadeira
} while (condicao); // repare no ponto e vírgula!O laço while
Aqui está o exemplo clássico, contando de 1 a 10:
1#include <iostream>
2
3int main() {
4 int contador = 1; // 1. início
5
6 while (contador <= 10) { // 2. verificação
7 std::cout << "O valor do contador é " << contador << "\n";
8 contador++; // 3. passo: sem isto, o laço nunca acaba
9 }
10
11 std::cout << "Pronto! Agora o contador vale " << contador << "\n";
12}Execução de exemplo:
1O valor do contador é 1
2O valor do contador é 2
3O valor do contador é 3
4O valor do contador é 4
5O valor do contador é 5
6O valor do contador é 6
7O valor do contador é 7
8O valor do contador é 8
9O valor do contador é 9
10O valor do contador é 10
11Pronto! Agora o contador vale 11Passo a passo: contador começa em 1. 1 ≤ 10? Sim, então o corpo imprime e soma um. De volta à verificação: 2 ≤ 10? Sim… e assim por diante, até contador virar 11. Aí 11 ≤ 10 é falso, e o programa segue depois do laço. Por isso a última linha diz 11: o laço para justamente porque o contador passou de 10.
Os três ingredientes
Quase todo laço while tem as mesmas três partes. Deixe uma de fora, ou erre nela, e o laço se comporta mal:

Quando você não sabe quantas vezes
Dobre uma folha de papel até a Lua
Uma folha de papel tem cerca de 0,1 mm de espessura. Cada vez que você a dobra ao meio, a espessura dobra. Quantas dobras até ela alcançar a Lua, a 384.400 km de distância? Difícil fazer essa conta de cabeça, então deixe um laço while descobrir:
1#include <iostream>
2
3int main() {
4 double espessuraEmMetros = 0.0001; // uma folha de papel: 0,1 mm
5 const double distanciaAteALua = 384400000.0; // 384.400 km
6 int dobras = 0;
7
8 while (espessuraEmMetros < distanciaAteALua) {
9 espessuraEmMetros *= 2; // cada dobra dobra a espessura
10 dobras++;
11 }
12
13 std::cout << "Dobras para chegar à Lua: " << dobras << "\n";
14 std::cout << "Espessura final: " << espessuraEmMetros / 1000 << " km\n";
15}Execução de exemplo:
Dobras para chegar à Lua: 42
Espessura final: 439805 kmSó 42! Aqui está a viagem inteira, dobra por dobra:

(Na vida real, ninguém dobrou uma folha de papel mais do que uma dúzia de vezes, mais ou menos. Mas a matemática, e o laço, não ligam para isso.)
Os números de granizo
Aqui vai um quebra-cabeça famoso. Escolha um número inteiro qualquer. Se for par, divida por 2. Se for ímpar, triplique e some 1. Repita até chegar ao 1. Quantos passos isso leva?
1#include <iostream>
2
3int main() {
4 long long numero = 27;
5 int passos = 0;
6 long long maior = numero;
7
8 while (numero != 1) {
9 if (numero % 2 == 0) {
10 numero = numero / 2;
11 } else {
12 numero = 3 * numero + 1;
13 }
14 passos++;
15 if (numero > maior) maior = numero;
16 }
17
18 std::cout << "O 27 chega ao 1 depois de " << passos << " passos\n";
19 std::cout << "Maior valor no caminho: " << maior << "\n";
20}Execução de exemplo:
O 27 chega ao 1 depois de 111 passos
Maior valor no caminho: 9232Rodamos o mesmo laço para todos os números iniciais de 1 a 30:

E aqui está a viagem maluca que o 27 faz até descer:

Desmontando um número, dígito por dígito
% 10 dá o último dígito de um número, e / 10 o arranca fora. Repita até não sobrar nada:
1#include <iostream>
2
3int main() {
4 int numero = 90210;
5 int quantidadeDeDigitos = 0;
6 int somaDosDigitos = 0;
7
8 while (numero > 0) {
9 somaDosDigitos += numero % 10; // o último dígito
10 numero /= 10; // arranca o último dígito
11 quantidadeDeDigitos++;
12 }
13
14 std::cout << "Dígitos: " << quantidadeDeDigitos << ", soma dos dígitos: " << somaDosDigitos << "\n";
15}Dígitos: 5, soma dos dígitos: 12Lendo até um sinal de parada
Uma sentinela é um valor especial que quer dizer "terminei". Este programa lê notas até o usuário digitar -1:
1#include <iostream>
2
3int main() {
4 int total = 0;
5 int quantidade = 0;
6 int nota;
7
8 std::cout << "Digite as notas (-1 para terminar): ";
9 std::cin >> nota;
10 while (nota != -1) {
11 total += nota;
12 quantidade++;
13 std::cin >> nota;
14 }
15
16 if (quantidade > 0) {
17 std::cout << quantidade << " notas, média " << static_cast<double>(total) / quantidade << "\n";
18 } else {
19 std::cout << "Nenhuma nota digitada\n";
20 }
21}Execução de exemplo:
Digite as notas (-1 para terminar): 90 85 77 -1
3 notas, média 84Se o primeiro valor já for -1, o corpo do laço nunca roda, e o programa diz "Nenhuma nota digitada". Esse comportamento de "zero vezes está tudo bem" é exatamente o propósito do laço while.
O laço do-while
Um do-while roda o corpo primeiro e verifica a condição depois. Então o corpo sempre roda pelo menos uma vez. Aqui está a diferença num programa só, com uma condição que já começa falsa:
1#include <iostream>
2
3int main() {
4 int numero = 2;
5
6 do {
7 std::cout << "o do-while vê " << numero << "\n";
8 numero++;
9 } while (numero < 2);
10
11 numero = 2;
12 while (numero < 2) {
13 std::cout << "o while vê " << numero << "\n";
14 numero++;
15 }
16
17 std::cout << "Fim\n";
18}o do-while vê 2
FimO do-while imprimiu uma vez antes de descobrir que 3 < 2 é falso. O laço while verificou 2 < 2 primeiro, achou falso e nunca rodou o corpo.
Perfeito para: perguntar até a resposta ser válida
Não dá para conferir uma resposta antes de fazer a pergunta, e é por isso que validar entrada é o trabalho clássico do do-while:
1#include <iostream>
2
3int main() {
4 int avaliacao;
5
6 do {
7 std::cout << "Dê uma nota de 1 a 5 ao filme: ";
8 std::cin >> avaliacao;
9 if (avaliacao < 1 || avaliacao > 5) {
10 std::cout << " Isso não está entre 1 e 5, tente de novo.\n";
11 }
12 } while (avaliacao < 1 || avaliacao > 5);
13
14 std::cout << "Obrigado! Você deu " << avaliacao << " estrelas.\n";
15}Execução de exemplo:
1Dê uma nota de 1 a 5 ao filme: 7
2 Isso não está entre 1 e 5, tente de novo.
3Dê uma nota de 1 a 5 ao filme: 0
4 Isso não está entre 1 e 5, tente de novo.
5Dê uma nota de 1 a 5 ao filme: 4
6Obrigado! Você deu 4 estrelas.Perfeito para: menus
Um menu precisa aparecer pelo menos uma vez e continuar voltando até o usuário escolher "sair":
1#include <iostream>
2
3int main() {
4 int opcao;
5 int cafes = 0;
6
7 do {
8 std::cout << "1) Pedir café 2) Ver total 0) Sair\n> ";
9 std::cin >> opcao;
10 if (opcao == 1) {
11 cafes++;
12 std::cout << "Café pedido!\n";
13 } else if (opcao == 2) {
14 std::cout << "Você pediu " << cafes << " café(s).\n";
15 }
16 } while (opcao != 0);
17
18 std::cout << "Tchau!\n";
19}Execução de exemplo:
11) Pedir café 2) Ver total 0) Sair
2> 1
3Café pedido!
41) Pedir café 2) Ver total 0) Sair
5> 1
6Café pedido!
71) Pedir café 2) Ver total 0) Sair
8> 2
9Você pediu 2 café(s).
101) Pedir café 2) Ver total 0) Sair
11> 0
12Tchau!Perfeito para: jogos
Um jogo de adivinhação: continue perguntando até o palpite estar certo. Você precisa de pelo menos um palpite, então o do-while se encaixa naturalmente:
1#include <iostream>
2
3int main() {
4 const int segredo = 37;
5 int palpite;
6 int tentativas = 0;
7
8 do {
9 std::cout << "Palpite (1-100): ";
10 std::cin >> palpite;
11 tentativas++;
12 if (palpite < segredo) {
13 std::cout << " Mais alto!\n";
14 } else if (palpite > segredo) {
15 std::cout << " Mais baixo!\n";
16 }
17 } while (palpite != segredo);
18
19 std::cout << "Acertou em " << tentativas << " tentativas!\n";
20}Execução de exemplo:
1Palpite (1-100): 50
2 Mais baixo!
3Palpite (1-100): 25
4 Mais alto!
5Palpite (1-100): 37
6Acertou em 3 tentativas!O jeito de escolher cada palpite faz uma diferença enorme. Pusemos um programa para jogar com todos os números secretos de 1 a 100 usando duas estratégias: contar 1, 2, 3…, ou sempre chutar o meio do que sobrou:

O mesmo laço, uma regra mais esperta dentro dele, e 7 palpites sempre bastam. Essa ideia de dividir ao meio se chama busca binária e aparece em todo canto da computação.
Pilotando o laço: break e continue
Duas palavras-chave deixam você mudar o rumo de dentro do corpo:
breaksai do laço na hora.continuepula o resto desta volta e vai direto para a verificação.

1#include <iostream>
2
3int main() {
4 int numero = 0;
5 while (true) {
6 numero++;
7 if (numero % 3 == 0) {
8 continue; // pula os múltiplos de 3 e volta para a verificação
9 }
10 if (numero > 10) {
11 break; // sai do laço de vez
12 }
13 std::cout << numero << " ";
14 }
15 std::cout << "\nParou no " << numero << "\n";
16}1 2 4 5 7 8 10
Parou no 11while (true) parece rodar para sempre, e rodaria, sem o break. É um padrão comum e prático quando o lugar natural de parar fica no meio do corpo.
Laços infinitos: o laço que nunca acaba
O bug de laço mais comum é um laço que nunca para. Aqui estão três jeitos clássicos de escrever um:

O terceiro surpreende quase todo mundo, então vamos vê-lo acontecer (com uma rede de proteção para parar depois de 12 voltas):
1#include <iostream>
2
3int main() {
4 double valor = 0.0;
5 int passos = 0;
6
7 std::cout.precision(17);
8 while (valor != 1.0 && passos < 12) { // passos < 12 é uma rede de proteção
9 valor += 0.1;
10 passos++;
11 std::cout << "passo " << passos << ": " << valor << "\n";
12 }
13}1passo 1: 0.10000000000000001
2passo 2: 0.20000000000000001
3passo 3: 0.30000000000000004
4passo 4: 0.40000000000000002
5passo 5: 0.5
6passo 6: 0.59999999999999998
7passo 7: 0.69999999999999996
8passo 8: 0.79999999999999993
9passo 9: 0.89999999999999991
10passo 10: 0.99999999999999989
11passo 11: 1.0999999999999999
12passo 12: 1.2Os computadores guardam decimais em binário, e 0,1 não pode ser guardado de forma exata, assim como 1/3 não pode ser escrito exatamente como 0,333… em decimal. Os errinhos se acumulam, e o valor nunca cai exatamente em 1.0. A solução é nunca esperar por um decimal exato: compare com < em vez de !=, ou conte passos inteiros com um int.
Que laço usar?

while | do-while | for | |
|---|---|---|---|
| Verifica a condição | Antes de cada volta | Depois de cada volta | Antes de cada volta |
| Mínimo de execuções | 0 | 1 | 0 |
| Melhor para | "Até algo acontecer" | Menus, validar entrada, "jogar de novo?" | Contar, percorrer arrays |
| Exemplo clássico | Ler até uma sentinela | "Digite de 1 a 5" | for (int i = 0; i < 10; i++) |
A mesma ideia em outras linguagens
JavaScript tem os dois laços, igualzinho ao C++:
1let contador = 1;
2while (contador <= 3) {
3 console.log("contador vale " + contador);
4 contador++;
5}Python tem o laço while, mas não tem do-while. O substituto de costume é um while True com break:
1while True:
2 resposta = input("Digite sim para continuar: ")
3 if resposta == "sim":
4 breakHora de praticar
Tente fazer estes antes de espiar as respostas. Copie cada programa num arquivo, compile com g++ -std=c++20 -Wall programa.cpp e rode.
Exercício 1: Adivinhe a saída (aquecimento). O que isto imprime? Preste atenção no último número.
1int numero = 5;
2while (numero > 0) {
3 std::cout << numero << " ";
4 numero -= 2;
5}
6std::cout << "| " << numero << "\n";Exercício 2: Ache o erro. Esta contagem regressiva nunca termina. Por quê?
1int segundos = 10;
2while (segundos > 0) {
3 std::cout << segundos << "... ";
4 segundos++;
5}
6std::cout << "Decolar!\n";Exercício 3: Inverta um número. Usando % 10 e / 10, transforme 1234 em 4321.
Exercício 4: Três tentativas. Peça uma senha com um laço do-while. Pare quando ela estiver certa (4321) ou depois de 3 tentativas erradas, e então imprima Desbloqueado! ou Tentativas demais. Cartão bloqueado.
Exercício 5: Máximo divisor comum (desafio). Há mais de 2.000 anos, Euclides descobriu um laço que acha o maior número que divide dois números sem deixar resto: enquanto o segundo número não for 0, troque o par (primeiro, segundo) por (segundo, primeiro % segundo). Ache o máximo divisor comum de 1071 e 462, imprimindo cada passo.
Quiz rápido
- A condição de um laço while é falsa já na primeira verificação. Quantas vezes o corpo roda? E num do-while?
- O que está faltando em
int contador = 0; while (contador < 5) { std::cout << contador; }? - Qual é a diferença entre
breakecontinue? - Por que
while (valor != 1.0)é perigoso quandovalorsobe de 0.1 em 0.1? - Que laço combina com "mostrar o menu até o usuário escolher Sair"?
Respostas
Exercício 1: 5 3 1 | -1. O laço imprime 5, 3 e 1. Depois do 1, ele subtrai 2 e chega a -1, a verificação -1 > 0 falha e o laço para. A variável fica com o último valor, -1.
5 3 1 | -1Exercício 2: segundos++ se afasta da linha de chegada: 10, 11, 12… e segundos > 0 continua verdadeiro para sempre. O certo é segundos--:
1#include <iostream>
2
3int main() {
4 int segundos = 10;
5 while (segundos > 0) {
6 std::cout << segundos << "... ";
7 segundos--;
8 }
9 std::cout << "Decolar!\n";
10}10... 9... 8... 7... 6... 5... 4... 3... 2... 1... Decolar!Exercício 3: A cada volta, empurre o resultado um dígito para a esquerda (* 10) e some o último dígito do número.
1#include <iostream>
2
3int main() {
4 int numero = 1234;
5 int invertido = 0;
6
7 while (numero > 0) {
8 invertido = invertido * 10 + numero % 10;
9 numero /= 10;
10 }
11
12 std::cout << "Invertido: " << invertido << "\n";
13}Invertido: 4321Exercício 4: A condição junta os dois motivos para continuar perguntando: a senha está errada e ainda há tentativas.
1#include <iostream>
2
3int main() {
4 const int senhaCorreta = 4321;
5 int senha;
6 int tentativas = 0;
7
8 do {
9 std::cout << "Digite a senha: ";
10 std::cin >> senha;
11 tentativas++;
12 } while (senha != senhaCorreta && tentativas < 3);
13
14 if (senha == senhaCorreta) {
15 std::cout << "Desbloqueado!\n";
16 } else {
17 std::cout << "Tentativas demais. Cartão bloqueado.\n";
18 }
19}Duas execuções de exemplo:
Digite a senha: 1111
Digite a senha: 4321
Desbloqueado!1Digite a senha: 1
2Digite a senha: 2
3Digite a senha: 3
4Tentativas demais. Cartão bloqueado.Exercício 5: Três voltas bastam:
1#include <iostream>
2
3int main() {
4 int primeiro = 1071;
5 int segundo = 462;
6
7 while (segundo != 0) {
8 int resto = primeiro % segundo;
9 std::cout << primeiro << " % " << segundo << " = " << resto << "\n";
10 primeiro = segundo;
11 segundo = resto;
12 }
13
14 std::cout << "Máximo divisor comum: " << primeiro << "\n";
15}11071 % 462 = 147
2462 % 147 = 21
3147 % 21 = 0
4Máximo divisor comum: 21Quiz: (1) Zero vezes no while; uma vez no do-while. (2) O passo: contador nunca muda, então o laço nunca acaba. Acrescente contador++;. (3) break sai do laço de vez; continue pula o resto da volta atual e vai para a verificação. (4) 0,1 não pode ser guardado de forma exata, então valor pula de 0.99999999999999989 para 1.0999999999999999 e nunca é exatamente 1.0. (5) do-while, porque o menu precisa aparecer pelo menos uma vez.
Cola rápida
| Eu quero… | Escreva |
|---|---|
| Repetir enquanto algo for verdadeiro | while (condicao) { ... } |
| Rodar pelo menos uma vez e depois repetir | do { ... } while (condicao); |
| Contar de 1 a 10 | int contador = 1; while (contador <= 10) { ...; contador++; } |
| Ler até um valor de parada | std::cin >> valor; while (valor != -1) { ...; std::cin >> valor; } |
| Perguntar até a resposta ser válida | do { pergunta; } while (resposta inválida); |
| Sair do laço mais cedo | break; |
| Pular para a próxima volta | continue; |
Repetir até um break | while (true) { ...; if (terminou) break; } |
| Desmontar um número | while (numero > 0) { digito = numero % 10; numero /= 10; } |
| Parar um programa travado | Ctrl+C no terminal |
Resumindo
Os laços while são o jeito de um programa dizer "continue até…":
whileverifica antes e pode rodar zero vezes;do-whileverifica depois e sempre roda pelo menos uma vez.- Todo laço precisa de um início, uma verificação e um passo que caminhe até a linha de chegada.
- Use while quando não souber a quantidade de antemão: dobrar até a Lua levou 42 voltas, e o 27 precisou de 111 passos para chegar ao 1.
- Use do-while em menus, validação de entrada e jogos.
breaksai de um laço;continuepula para a próxima volta.- Laços infinitos nascem de um passo esquecido, um passo na direção errada ou da espera por um decimal exato.
Conheça o especialista em contagem em O Laço For; para colocar decisões dentro dos seus laços, leia O Comando If; e para percorrer dados de verdade, Arrays em C++.
Leia a seguir

O Que É a Linguagem de Programação Rust? Um Guia Simples da Linguagem Rápida Que Não Deixa Você Travar
Um guia simples e sem jargões sobre o Rust, a linguagem tão rápida quanto o C que impede famílias inteiras de erros de memória antes de o programa rodar. Entenda a ideia de posse, por que gigantes da tecnologia o adotam e onde ele é usado.

O Que É a Linguagem de Programação Go? Um Guia Simples da Linguagem da Nuvem
Um guia simples e sem jargões sobre o Go, a linguagem simples e rápida que o Google criou para a nuvem. Entenda o que são goroutines, por que um programa Go é um arquivo só e como o Go passou a mover o Docker, o Kubernetes e boa parte da internet.

O Que É a Linguagem de Programação Ruby? Um Guia Simples da Linguagem Feita para a Felicidade
Um guia simples e sem jargões sobre o Ruby, a linguagem de programação feita para deixar os programadores felizes. Entenda por que o código Ruby parece inglês, como o Ruby on Rails move sites como GitHub e Shopify, e onde o Ruby brilha.
Comentários
Seja gentil e específico. Comentários com links de contas novas aparecem depois da análise de um moderador.