C++ do-while
Na aula while, a condição é testada antes de cada volta, e por isso o corpo pode não rodar nenhuma vez. Muitas vezes, porém, você precisa fazer a coisa ao menos uma vez antes de decidir se repete: mostrar um menu, pedir uma nota, perguntar "quer mais um?". Para esses casos, o C++ tem o do-while: "faça isto, e repita enquanto…".
- Como escrever um
do-while(e onde vai o ponto e vírgula). - Por que o corpo de um
do-whileroda pelo menos uma vez. - Como pedir um valor até ele ser válido (uma nota de 0 a 10).
- Como montar um menu de opções com
do-whileeswitch. - Quando usar
do-whilee quando usarwhile. - Os dois erros mais comuns: o
;esquecido e a variável criada dentro do bloco.
Os programas foram compilados com o g++ 15 na máquina fictícia da Ana, na pasta ~/cpp, com g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa. Nos programas que leem do teclado, o que aparece depois de cada pergunta foi digitado pela Ana.
A ideia: provar a comida antes de pôr mais sal
Quem cozinha não pergunta "a comida está sem sal?" antes de provar. Primeiro prova, depois decide:
- Prova a comida.
- Está sem sal? Sim → põe uma pitada e volta ao passo 1.
- Está sem sal? Não → pronto, desliga o fogo.
Você sempre prova pelo menos uma vez, porque só sabe a resposta depois de provar. É essa a diferença entre os dois laços:
while | do-while | |
|---|---|---|
| Ordem | pergunta → faz → pergunta → faz… | faz → pergunta → faz → pergunta… |
| No dia a dia | "Enquanto tiver louça, lave um prato" (pia vazia: não lava nenhum) | "Prove; enquanto estiver sem sal, ponha sal e prove de novo" |
1. A forma do do-while
#include <iostream>
int main() {
int i = 1;
do {
std::cout << "Volta " << i << '\n';
i++;
} while (i <= 5);
std::cout << "Fim!\n";
}
- do
- "Faça". Marca o começo do laço. Não tem condição aqui: o programa entra direto no corpo.
- { … }
- O corpo: as linhas que se repetem. Roda uma vez antes de qualquer pergunta.
- while
- "Enquanto". Vem depois da chave que fecha o corpo.
- (i <= 5)
- A condição. É testada no fim de cada volta: se for verdadeira, o programa volta para o
do; se for falsa, segue em frente. - ;
- O ponto e vírgula obrigatório no fim. Ele existe porque o
do-whiletermina numa condição, não numa chave. É o detalhe que mais se esquece (veja Quando dá errado).
$ g++ -std=c++23 -Wall -Wextra contar.cpp -o contar $ ./contar Volta 1 Volta 2 Volta 3 Volta 4 Volta 5 Fim!
A saída é igual à do while da aula anterior. Quando a condição é verdadeira no começo, os dois laços se comportam do mesmo jeito. A diferença aparece quando ela já começa falsa.
2. Pelo menos uma vez: a diferença na prática
Este programa faz a mesma coisa com os dois laços. Nos dois, a variável começa em 10 e a condição é "menor que 5", que já é falsa desde o início:
#include <iostream>
int main() {
int a = 10;
while (a < 5) {
std::cout << "while: " << a << '\n';
a++;
}
int b = 10;
do {
std::cout << "do-while: " << b << '\n';
b++;
} while (b < 5);
std::cout << "Fim\n";
}
$ g++ -std=c++23 -Wall -Wextra comparar.cpp -o comparar $ ./comparar do-while: 10 Fim
- O
whileperguntou primeiro:10 < 5? Não. O corpo não rodou, e nada apareceu. - O
do-whilerodou o corpo primeiro (mostroudo-while: 10,bvirou 11) e só então perguntou:11 < 5? Não. Parou depois de uma volta.
Essa é a regra inteira do do-while: o corpo roda no mínimo uma vez, não importa a condição.
3. Pedir até a resposta ser válida
O uso mais comum do do-while é validar uma entrada. A Ana está lançando notas, que vão de 0 a 10. Se ela digitar algo fora disso, o programa deve perguntar de novo. Repare que a pergunta precisa ser feita pelo menos uma vez: é o caso perfeito.
#include <iostream>
int main() {
int nota = 0;
do {
std::cout << "Digite a nota (0 a 10): ";
std::cin >> nota;
} while (nota < 0 || nota > 10);
std::cout << "Nota registrada: " << nota << '\n';
}
- int nota = 0;
- A variável é criada antes do
do, porque a condição dowhile, lá embaixo, precisa enxergá-la. (Criá-la dentro das chaves dá erro, como você vai ver.) - std::cin >> nota;
- Lê a nota (veja Entrada com cin). Aparece uma vez só no código, ao contrário da versão com
while. - nota < 0 || nota > 10
- "A nota é menor que 0 ou maior que 10", ou seja, inválida (o
||está em Operadores Lógicos). Enquanto ela for inválida, repete.
$ g++ -std=c++23 -Wall -Wextra nota.cpp -o nota $ ./nota Digite a nota (0 a 10): 15 Digite a nota (0 a 10): -2 Digite a nota (0 a 10): 8 Nota registrada: 8
A condição do while descreve quando repetir, não quando parar. Por isso ela é "a nota é inválida". Uma dica para escrever: pense na condição de parada ("nota entre 0 e 10") e escreva o contrário dela.
Avisando o erro
Repetir a pergunta sem explicação confunde. Um if dentro do corpo resolve:
#include <iostream>
int main() {
int nota = 0;
do {
std::cout << "Digite a nota (0 a 10): ";
std::cin >> nota;
if (nota < 0 || nota > 10) {
std::cout << "Nota inválida! Tente de novo.\n";
}
} while (nota < 0 || nota > 10);
std::cout << "Nota registrada: " << nota << '\n';
}
$ g++ -std=c++23 -Wall -Wextra nota2.cpp -o nota2 $ ./nota2 Digite a nota (0 a 10): 15 Nota inválida! Tente de novo. Digite a nota (0 a 10): -2 Nota inválida! Tente de novo. Digite a nota (0 a 10): 8 Nota registrada: 8
A condição aparece duas vezes (no if e no while). Para não repetir, você poderia guardá-la numa variável bool invalida = nota < 0 || nota > 10;, mas aí ela precisaria ser criada antes do do. Para quem está começando, repetir a condição é aceitável.
Este programa só se protege de números fora do intervalo. Se a entrada não for um número, o std::cin entra em estado de falha e é preciso "limpá-lo". Isso tem aula própria: Validar a Entrada.
Missão: este programa aceita qualquer nota: com a entrada 15 -2 8, ele registra o 15. Coloque a pergunta e o std::cin dentro de um do { … } while ( … ); para repetir enquanto a nota for menor que 0 ou maior que 10. O resultado deve ser Nota registrada: 8.
#include <iostream>
int main() {
int nota = 0;
std::cout << "Digite a nota (0 a 10): ";
std::cin >> nota;
std::cout << "Nota registrada: " << nota << '\n';
}
#include <iostream>
int main() {
int nota = 0;
do {
std::cout << "Digite a nota (0 a 10): ";
std::cin >> nota;
} while (nota < 0 || nota > 10);
std::cout << "Nota registrada: " << nota << '\n';
}
4. A soma até o 0, sem repetir a leitura
Na aula while, a soma até o usuário digitar 0 tinha a pergunta e o std::cin escritos duas vezes. Com do-while, uma vez basta:
#include <iostream>
int main() {
int numero = 0;
int soma = 0;
do {
std::cout << "Digite um número (0 para parar): ";
std::cin >> numero;
soma += numero;
} while (numero != 0);
std::cout << "Soma: " << soma << '\n';
}
$ g++ -std=c++23 -Wall -Wextra soma.cpp -o soma $ ./soma Digite um número (0 para parar): 10 Digite um número (0 para parar): 25 Digite um número (0 para parar): 7 Digite um número (0 para parar): 0 Soma: 42
Repare num detalhe: aqui o 0 entra na soma, porque o soma += numero acontece antes do teste. Somar 0 não muda nada, então o resultado está certo. Mas se a sentinela fosse -1, a soma sairia errada (ficaria 1 a menos). Nesse caso, ou você usa a versão com while, ou soma só if (numero != -1).
5. Menu de opções
Todo programa de terminal com menu tem o mesmo formato: mostra as opções, lê a escolha, faz o que foi pedido e mostra o menu de novo, até a pessoa escolher "Sair". O menu precisa aparecer pelo menos uma vez, então é do-while. Para tratar cada opção, o switch é a ferramenta natural:
#include <iostream>
int main() {
int opcao = 0;
int itens = 0;
do {
std::cout << "\n=== Lojinha da Ana ===\n";
std::cout << "1 - Adicionar um item\n";
std::cout << "2 - Ver o carrinho\n";
std::cout << "0 - Sair\n";
std::cout << "Opção: ";
std::cin >> opcao;
switch (opcao) {
case 1:
itens++;
std::cout << "Item adicionado.\n";
break;
case 2:
std::cout << "Itens no carrinho: " << itens << '\n';
break;
case 0:
std::cout << "Até logo!\n";
break;
default:
std::cout << "Opção inválida.\n";
}
} while (opcao != 0);
}
$ g++ -std=c++23 -Wall -Wextra menu.cpp -o menu $ ./menu === Lojinha da Ana === 1 - Adicionar um item 2 - Ver o carrinho 0 - Sair Opção: 1 Item adicionado. === Lojinha da Ana === 1 - Adicionar um item 2 - Ver o carrinho 0 - Sair Opção: 1 Item adicionado. === Lojinha da Ana === 1 - Adicionar um item 2 - Ver o carrinho 0 - Sair Opção: 2 Itens no carrinho: 2 === Lojinha da Ana === 1 - Adicionar um item 2 - Ver o carrinho 0 - Sair Opção: 7 Opção inválida. === Lojinha da Ana === 1 - Adicionar um item 2 - Ver o carrinho 0 - Sair Opção: 0 Até logo!
Pontos importantes deste programa:
itenseopcaonascem fora do laço.itensprecisa sobreviver entre as voltas (é um acumulador);opcaoprecisa ser vista pela condição dowhile.- O
breakde cadacasesai só doswitch, não do laço. É por isso que, depois de "Item adicionado.", o menu aparece de novo. (Mais sobre isso em break e continue.) - A opção
0mostra "Até logo!" noswitche, em seguida, a condiçãoopcao != 0fica falsa: o laço termina. - O
\nno começo do título deixa uma linha em branco entre um menu e outro, para facilitar a leitura.
Experimente: a entrada já vem pronta: 1 1 1 2 0 (três itens, ver o carrinho, sair). Acrescente uma opção 3 - Esvaziar o carrinho, que faz itens = 0;, e mude a entrada para testá-la.
#include <iostream>
int main() {
int opcao = 0;
int itens = 0;
do {
std::cout << "\n=== Lojinha da Ana ===\n";
std::cout << "1 - Adicionar um item\n";
std::cout << "2 - Ver o carrinho\n";
std::cout << "0 - Sair\n";
std::cout << "Opção: ";
std::cin >> opcao;
switch (opcao) {
case 1:
itens++;
std::cout << "Item adicionado.\n";
break;
case 2:
std::cout << "Itens no carrinho: " << itens << '\n';
break;
case 0:
std::cout << "Até logo!\n";
break;
default:
std::cout << "Opção inválida.\n";
}
} while (opcao != 0);
}
6. "Deseja continuar?"
Outra forma clássica: fazer algo e perguntar se a pessoa quer repetir. A resposta é um caractere (char, veja Caracteres). Aceitar s e S evita irritar quem está com o Caps Lock ligado:
#include <iostream>
int main() {
char resposta = 'n';
int pedidos = 0;
do {
pedidos++;
std::cout << "Pedido " << pedidos << " anotado. Mais um? (s/n) ";
std::cin >> resposta;
} while (resposta == 's' || resposta == 'S');
std::cout << "Total de pedidos: " << pedidos << '\n';
}
$ g++ -std=c++23 -Wall -Wextra continuar.cpp -o continuar $ ./continuar Pedido 1 anotado. Mais um? (s/n) s Pedido 2 anotado. Mais um? (s/n) S Pedido 3 anotado. Mais um? (s/n) n Total de pedidos: 3
Qualquer resposta que não seja s ou S encerra: n, x, 9… Isso é proposital: na dúvida, o programa para.
Qual usar: do-while × while
while (cond) { … } | do { … } while (cond); | |
|---|---|---|
| Quando testa | Antes de cada volta | Depois de cada volta |
| Mínimo de voltas | 0 | 1 |
| Ponto e vírgula no fim | Não (termina em }) | Sim (termina em );) |
| A variável da condição | Precisa ter valor antes do laço | Pode receber o valor dentro do corpo, mas deve ser criada antes |
| Bom para | Processar enquanto houver algo (estoque, saldo, dados) | Menus, validar entrada, "deseja continuar?" |
| Frequência no código real | Muito usado | Bem menos usado |
Na dúvida, comece pelo while. Se você perceber que está escrevendo a mesma linha antes do laço e no fim do corpo (como a leitura da soma), troque por do-while. Uma terceira opção, que muita gente prefere para menus, é o while (true) com break, que você vai ver em break e continue.
Quando dá errado
#include <iostream>
int main() {
int i = 1;
do {
std::cout << i << '\n';
i++;
} while (i <= 3)
std::cout << "Fim\n";
}
$ g++ -std=c++23 -Wall -Wextra semponto.cpp -o semponto
semponto.cpp: In function ‘int main()’:
semponto.cpp:8:21: error: expected ‘;’ before ‘std’
8 | } while (i <= 3)
| ^
| ;
9 | std::cout << "Fim\n";
| ~~~
O que significa: "esperava ; antes de std". O compilador chegou ao fim do while (i <= 3), esperava o ponto e vírgula e encontrou o std da linha seguinte. Ele até desenha o ; no lugar onde ele falta (linha 8, coluna 21).
No editor do guia, o Clang é ainda mais direto: error: expected ';' after do/while statement ("esperava ; depois da instrução do/while").
Como consertar: } while (i <= 3);. Lembre: no do-while o ; é obrigatório; no while comum, ele é um erro (vira um laço vazio, veja while).
#include <iostream>
int main() {
do {
int opcao = 0;
std::cout << "Opção: ";
std::cin >> opcao;
} while (opcao != 0);
}
$ g++ -std=c++23 -Wall -Wextra escopo.cpp -o escopo
escopo.cpp: In function ‘int main()’:
escopo.cpp:8:14: error: ‘opcao’ was not declared in this scope
8 | } while (opcao != 0);
| ^~~~~
O que significa: "opcao não foi declarada neste escopo". Uma variável criada entre { e } só existe até a }. A condição do while fica depois da chave que fecha o corpo, onde opcao já não existe. É um erro muito comum, porque a condição parece "fazer parte" do laço. (A ideia de escopo tem aula própria: Escopo.)
No editor do guia: error: use of undeclared identifier 'opcao' ("uso de identificador não declarado").
Como consertar: crie a variável antes do do (int opcao = 0;) e, dentro do corpo, só leia o valor (std::cin >> opcao;).
O que aconteceu: a condição do while não combina com a opção de saída. Se o menu diz "0 - Sair" mas a condição é while (opcao != 9), o 0 não encerra. Se a condição é while (opcao == 0), o laço só repete quando a pessoa pede para sair, o contrário do que se quer.
Como consertar: leia a condição em voz alta: "repita enquanto a opção for diferente da de sair" → while (opcao != 0).
O que aconteceu: se o std::cin >> nota; ficar fora do do { … }, a nota inválida nunca é lida de novo: o corpo repete para sempre com o mesmo valor. Teste com timeout 3 ./nota e pare com Ctrl+C (veja o laço infinito).
Como consertar: a linha que muda a variável da condição precisa estar dentro do corpo.
Referência
| Forma | O que faz |
|---|---|
do { … } while (condição); | Roda o corpo, depois testa; se verdadeira, repete. Roda pelo menos 1 vez. |
do { std::cin >> x; } while (x < 0 || x > 10); | Pede até o valor ser válido. |
do { menu; std::cin >> op; switch (op) { … } } while (op != 0); | Menu que repete até a opção de sair. |
do { …; std::cin >> r; } while (r == 's' || r == 'S'); | "Deseja continuar?" |
Exercícios
1. O que falta?
Complete o fim do laço (a condição já está escrita):
2. Condição da validação
Complete para repetir enquanto a idade for negativa:
3. Quantas voltas?
Quantas vezes o corpo roda em int x = 100; do { x++; } while (x < 50);?
4. Qual é a diferença essencial entre while e do-while?
5. Para um menu que aparece, executa a opção e aparece de novo até o usuário escolher "Sair", o mais natural é:
6. O g++ disse ‘resposta’ was not declared in this scope apontando para o while (resposta == 's') de um do-while. O que provavelmente aconteceu?
Missão final: o jogo de adivinhação
Missão: o número secreto é 7. Com um do-while, peça um palpite, conte a tentativa e diga É maior! ou É menor!, repetindo enquanto o palpite for diferente do secreto. No fim, mostre Acertou em N tentativas!. A entrada já traz os palpites 3 9 7, então a resposta deve ser Acertou em 3 tentativas!.
#include <iostream>
int main() {
const int secreto = 7;
int palpite = 0;
int tentativas = 0;
// escreva o do-while aqui
std::cout << "Acertou em " << tentativas << " tentativas!\n";
}
#include <iostream>
int main() {
const int secreto = 7;
int palpite = 0;
int tentativas = 0;
do {
std::cout << "Seu palpite: ";
std::cin >> palpite;
tentativas++;
if (palpite < secreto) {
std::cout << "É maior!\n";
} else if (palpite > secreto) {
std::cout << "É menor!\n";
}
} while (palpite != secreto);
std::cout << "Acertou em " << tentativas << " tentativas!\n";
}
No terminal, com a Ana digitando os palpites, a solução fica assim:
$ g++ -std=c++23 -Wall -Wextra adivinha.cpp -o adivinha $ ./adivinha Seu palpite: 3 É maior! Seu palpite: 9 É menor! Seu palpite: 7 Acertou em 3 tentativas!
Um jogo de verdade sorteia o número secreto: veja Números Aleatórios e o projeto Jogo de Adivinhação.
Resumo
do { corpo } while (condição);roda o corpo e depois testa. O corpo roda pelo menos uma vez.- O
;no fim é obrigatório; sem ele, o g++ dizexpected ‘;’. - A variável usada na condição deve ser criada antes do
do: o que nasce dentro das chaves não existe na linha dowhile. - Usos típicos: validar entrada ("pergunte até ser válido"), menus, "deseja continuar?".
- A condição diz quando repetir (nota inválida, opção diferente de 0), não quando parar.
- Na dúvida,
while; se a mesma linha aparece antes do laço e no fim do corpo,do-while.