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…".

Você vai aprender
  • Como escrever um do-while (e onde vai o ponto e vírgula).
  • Por que o corpo de um do-while roda 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-while e switch.
  • Quando usar do-while e quando usar while.
  • 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:

  1. Prova a comida.
  2. Está sem sal? Sim → põe uma pitada e volta ao passo 1.
  3. 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:

whiledo-while
Ordempergunta → 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-while termina 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 while perguntou primeiro: 10 < 5? Não. O corpo não rodou, e nada apareceu.
  • O do-while rodou o corpo primeiro (mostrou do-while: 10, b virou 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 do while, 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.

E se a Ana digitar uma letra?

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:

  • itens e opcao nascem fora do laço. itens precisa sobreviver entre as voltas (é um acumulador); opcao precisa ser vista pela condição do while.
  • O break de cada case sai só do switch, 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 0 mostra "Até logo!" no switch e, em seguida, a condição opcao != 0 fica falsa: o laço termina.
  • O \n no 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 testaAntes de cada voltaDepois de cada volta
Mínimo de voltas01
Ponto e vírgula no fimNão (termina em })Sim (termina em );)
A variável da condiçãoPrecisa ter valor antes do laçoPode receber o valor dentro do corpo, mas deve ser criada antes
Bom paraProcessar enquanto houver algo (estoque, saldo, dados)Menus, validar entrada, "deseja continuar?"
Frequência no código realMuito usadoBem 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

"expected ‘;’ before ‘std’" (esqueceu o ponto e vírgula)
#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).

"‘opcao’ was not declared in this scope" (variável criada dentro do bloco)
#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 menu volta mesmo depois de "Sair" (ou nunca volta)

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

Laço infinito na validação

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

FormaO 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):

do { i++; } while (i < 10)

2. Condição da validação

Complete para repetir enquanto a idade for negativa:

do { std::cin >> idade; } while ();

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++ diz expected ‘;’.
  • A variável usada na condição deve ser criada antes do do: o que nasce dentro das chaves não existe na linha do while.
  • 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.