C do while
O while faz a pergunta antes de cada volta: se a resposta já for "não" na primeira vez, o corpo nem roda. Mas há situações em que você precisa fazer a coisa pelo menos uma vez para só depois decidir se repete: mostrar um menu, pedir uma nota, perguntar "deseja continuar?". Para isso o C tem o do while ("faça … enquanto"): primeiro faz, depois pergunta.
- A forma do
do { … } while (condição);e por que o;no fim é obrigatório. - A diferença prática entre
whileedo while: zero voltas × pelo menos uma. - Como validar a entrada: pedir a nota de novo até ela estar entre 0 e 10.
- Como fazer um menu que repete até a pessoa escolher "Sair".
- Como perguntar "deseja continuar? (s/n)" com
scanf(" %c", …), e por que o espaço antes do%cimporta. - Os erros mais comuns e as mensagens reais do compilador.
Todos os programas foram compilados com o gcc 15 na máquina fictícia da Ana, na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa.
A ideia: provar a comida antes de pôr mais sal
Quem cozinha não pergunta "precisa de mais sal?" antes de provar. A ordem é:
- Prova a comida.
- Pergunta: ainda está sem sal? Sim → põe uma pitada e volta ao passo 1.
- Não → pronto, serve.
Você prova pelo menos uma vez, sempre, e só então decide se repete. Essa é a diferença entre os dois laços:
while | do while | |
|---|---|---|
| Quando testa a condição | Antes de cada volta | Depois de cada volta |
| Menor número de voltas | 0 | 1 |
| Comparação | "Tem louça? Então lave." | "Prove. Precisa de sal? Então prove de novo." |
1. A forma do do while
#include <stdio.h>
int main(void) {
int i = 1;
do {
printf("Volta %d\n", i);
i++;
} while (i <= 5);
printf("Fim! i agora vale %d\n", i);
return 0;
}
- do
- "Faça". Marca o começo do laço. Não tem condição aqui: o corpo começa a rodar direto.
- { … }
- O corpo, que roda pelo menos uma vez.
- while (i <= 5)
- A condição, testada depois de cada volta. Se for verdadeira, o programa volta para o
do; se for falsa, segue para a linha de baixo. - ;
- O ponto e vírgula no fim é obrigatório. O
do whileé o único laço que termina com;. Esquecer dá erro de compilação (veja Quando dá errado).
$ gcc -std=c23 -Wall -Wextra contar_do.c -o contar_do $ ./contar_do Volta 1 Volta 2 Volta 3 Volta 4 Volta 5 Fim! i agora vale 6
A saída é igual à do while da aula anterior. Quando a condição começa verdadeira, os dois laços fazem a mesma coisa. A diferença aparece quando ela começa falsa.
while na mesma linha da }
Assim, quem lê vê logo que aquele while é o fim de um do, e não o começo de um laço novo. É o estilo usado neste guia e na maioria dos projetos em C.
2. Pelo menos uma vez: a diferença na prática
Neste programa, os dois laços começam com o contador em 10 e a condição <= 5, que já é falsa:
#include <stdio.h>
int main(void) {
int i = 10;
while (i <= 5) {
printf("while: volta %d\n", i);
i++;
}
int j = 10;
do {
printf("do while: volta %d\n", j);
j++;
} while (j <= 5);
printf("Fim\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra umavez.c -o umavez $ ./umavez do while: volta 10 Fim
O while perguntou primeiro (10 <= 5? não) e não rodou nenhuma vez. O do while rodou o corpo, mostrou volta 10, e só então perguntou: como a resposta foi "não", parou. Por isso ele é a escolha quando a primeira volta é obrigatória.
3. Pedir até a resposta ser válida
Esta é a tarefa mais comum do do while. A Ana está lançando notas e uma nota só vale de 0 a 10. O programa precisa perguntar uma vez e, se a resposta for inválida, perguntar de novo:
#include <stdio.h>
int main(void) {
int nota = 0;
do {
printf("Digite a nota (0 a 10): ");
if (scanf("%d", ¬a) != 1) {
printf("Isso não é um número.\n");
return 1;
}
if (nota < 0 || nota > 10) {
printf("Nota inválida! Tente de novo.\n");
}
} while (nota < 0 || nota > 10);
printf("Nota registrada: %d\n", nota);
return 0;
}
- int nota = 0;
- A variável nasce fora do
do, porque a condição lá embaixo precisa enxergá-la (veja o erro ‘nota’ undeclared). - if (scanf("%d", ¬a) != 1)
- O
scanfdevolve quantos valores conseguiu ler. Se não for 1, a pessoa digitou algo que não é número. Aqui o programa avisa e termina comreturn 1(código de saída 1 = "deu errado"). Sem essa conferência, uma letra faria o laço repetir para sempre, como você viu em while. - nota < 0 || nota > 10
- "Nota menor que 0 ou maior que 10": a definição de nota inválida (veja Operadores Lógicos). O laço repete enquanto ela for inválida.
- printf("Nota inválida!…")
- Um aviso para a pessoa saber por que a pergunta voltou. Ele usa a mesma condição do
while.
$ gcc -std=c23 -Wall -Wextra nota.c -o nota $ ./nota 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 $ ./nota Digite a nota (0 a 10): oito Isso não é um número. $ echo $? 1
Com um while comum, você teria de escrever o printf e o scanf duas vezes (uma antes do laço e outra dentro). O do while escreve a pergunta uma vez só.
Dá para fazer, mas exige jogar fora o que ficou na entrada (o oito continua lá esperando, e o próximo scanf tropeçaria nele de novo). Isso é assunto da aula Validar a Entrada. Por enquanto, encerrar com uma mensagem clara já é muito melhor do que travar.
Missão: este programa pergunta a nota uma vez só e aceita qualquer coisa: com a entrada 15, -2, 8, ele registra o 15. Coloque a pergunta dentro de um do { … } while (…); para repetir enquanto a nota for menor que 0 ou maior que 10. A saída deve terminar com Nota registrada: 8.
#include <stdio.h>
int main(void) {
int nota = 0;
printf("Digite a nota (0 a 10): ");
if (scanf("%d", ¬a) != 1) {
return 1;
}
printf("Nota registrada: %d\n", nota);
return 0;
}
#include <stdio.h>
int main(void) {
int nota = 0;
do {
printf("Digite a nota (0 a 10): ");
if (scanf("%d", ¬a) != 1) {
return 1;
}
} while (nota < 0 || nota > 10);
printf("Nota registrada: %d\n", nota);
return 0;
}
4. A soma até o 0, sem repetir a leitura
Na aula do while, o programa que soma até o 0 tinha a pergunta e o scanf escritos duas vezes. Com do while, cada número é lido no começo da volta e a condição vem no fim:
#include <stdio.h>
int main(void) {
int numero = 0;
int soma = 0;
do {
printf("Digite um número (0 para parar): ");
if (scanf("%d", &numero) != 1) {
numero = 0;
}
soma += numero;
} while (numero != 0);
printf("Soma: %d\n", soma);
return 0;
}
$ gcc -std=c23 -Wall -Wextra soma_do.c -o soma_do $ ./soma_do 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 (soma += numero roda antes do teste). Como somar 0 não muda nada, o resultado é o mesmo. E se a leitura falhar (uma letra, ou o fim da entrada), o programa trata como se a pessoa tivesse digitado 0 e para.
5. Um menu que repete
Quase todo programa de terminal tem um menu: mostra as opções, a pessoa escolhe, o programa faz a tarefa e mostra o menu de novo, até ela escolher "Sair". O menu precisa aparecer pelo menos uma vez, então é do while. Cada opção é tratada com um switch:
#include <stdio.h>
int main(void) {
int opcao = 0;
int itens = 0;
do {
printf("\n=== Lojinha da Ana ===\n");
printf("1 - Vender um item\n");
printf("2 - Ver vendas\n");
printf("0 - Sair\n");
printf("Escolha: ");
if (scanf("%d", &opcao) != 1) {
opcao = 0;
}
switch (opcao) {
case 1:
itens++;
printf("Venda registrada.\n");
break;
case 2:
printf("Itens vendidos hoje: %d\n", itens);
break;
case 0:
printf("Até amanhã!\n");
break;
default:
printf("Opção inválida.\n");
}
} while (opcao != 0);
return 0;
}
$ gcc -std=c23 -Wall -Wextra menu.c -o menu $ ./menu === Lojinha da Ana === 1 - Vender um item 2 - Ver vendas 0 - Sair Escolha: 1 Venda registrada. === Lojinha da Ana === 1 - Vender um item 2 - Ver vendas 0 - Sair Escolha: 1 Venda registrada. === Lojinha da Ana === 1 - Vender um item 2 - Ver vendas 0 - Sair Escolha: 2 Itens vendidos hoje: 2 === Lojinha da Ana === 1 - Vender um item 2 - Ver vendas 0 - Sair Escolha: 7 Opção inválida. === Lojinha da Ana === 1 - Vender um item 2 - Ver vendas 0 - Sair Escolha: 0 Até amanhã!
- int itens = 0;
- O contador de vendas nasce fora do laço, para sobreviver de uma volta para outra.
- opcao = 0;
- Se a pessoa digitar uma letra, o programa trata como "Sair" em vez de mostrar o menu para sempre.
- break;
- Dentro do
switch, obreaksai só do switch, não do laço. O programa continua até owhile (opcao != 0). - while (opcao != 0);
- Repete o menu enquanto a escolha não for 0.
Experimente: esta caixa não tem entrada pronta. Clique em Rodar e digite as opções no terminal da caixa (Enter depois de cada uma). Venda alguns itens, veja as vendas, e saia com 0. Depois acrescente uma opção 3 - Cancelar uma venda que diminui itens.
#include <stdio.h>
int main(void) {
int opcao = 0;
int itens = 0;
do {
printf("\n=== Lojinha da Ana ===\n");
printf("1 - Vender um item\n");
printf("2 - Ver vendas\n");
printf("0 - Sair\n");
printf("Escolha: ");
if (scanf("%d", &opcao) != 1) {
opcao = 0;
}
switch (opcao) {
case 1:
itens++;
printf("Venda registrada.\n");
break;
case 2:
printf("Itens vendidos hoje: %d\n", itens);
break;
case 0:
printf("Até amanhã!\n");
break;
default:
printf("Opção inválida.\n");
}
} while (opcao != 0);
return 0;
}
6. "Deseja continuar? (s/n)"
Outra pergunta clássica no fim de cada volta. A resposta é uma letra, então a variável é um char (veja Caracteres) e o formato do scanf é %c:
#include <stdio.h>
int main(void) {
char resposta = 'n';
int pedidos = 0;
do {
pedidos++;
printf("Pedido %d anotado.\n", pedidos);
printf("Deseja fazer outro pedido? (s/n) ");
if (scanf(" %c", &resposta) != 1) {
resposta = 'n';
}
} while (resposta == 's' || resposta == 'S');
printf("Total de pedidos: %d\n", pedidos);
return 0;
}
- " %c"
- Lê um caractere. O espaço antes do
%cmanda oscanfpular espaços e quebras de linha antes de ler. Ele é essencial: sem ele, oscanflê o Enter da resposta anterior (veja Quando dá errado). - resposta == 's' || resposta == 'S'
- Aceita
sminúsculo ou maiúsculo. Letras vão entre aspas simples:'s'é um caractere;"s"seria um texto.
$ gcc -std=c23 -Wall -Wextra continuar.c -o continuar $ ./continuar Pedido 1 anotado. Deseja fazer outro pedido? (s/n) s Pedido 2 anotado. Deseja fazer outro pedido? (s/n) S Pedido 3 anotado. Deseja fazer outro pedido? (s/n) n Total de pedidos: 3
Qualquer resposta que não seja s ou S encerra: n, x, até o fim da entrada.
Qual usar: do while × while
| Situação | Laço | Por quê |
|---|---|---|
| Menu, "deseja continuar?", pedir até ser válido | do while | A primeira volta é obrigatória: só dá para testar depois de perguntar. |
| Vender enquanto houver estoque, dobrar até passar de 1000 | while | Pode ser que não haja nada a fazer (estoque zerado): 0 voltas é uma resposta válida. |
| Contar de 1 a 10, passar por todos os alunos | for | O número de voltas é conhecido. |
Na dúvida, pergunte-se: "faz sentido o corpo rodar zero vezes?". Se sim, while. Se não, do while. Na prática, o do while aparece bem menos que os outros dois, mas nas situações acima ele deixa o código mais curto e sem repetição.
Quando dá errado
; do fim)
#include <stdio.h>
int main(void) {
int i = 1;
do {
printf("%d\n", i);
i++;
} while (i <= 3)
printf("Fim\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra semponto.c -o semponto
semponto.c: In function ‘main’:
semponto.c:8:21: error: expected ‘;’ before ‘printf’
8 | } while (i <= 3)
| ^
| ;
9 | printf("Fim\n");
| ~~~~~~
O que significa: "esperava ; antes de printf". O compilador chegou ao printf da linha 9 ainda esperando o fim do do while. Ele até mostra onde o ; deveria estar (a linha com ; embaixo do ^). O Clang do editor diz: error: expected ';' after do/while statement.
Como consertar: ponha ; depois do ): } while (i <= 3);.
Missão: este é o programa acima. Rode, leia a mensagem do Clang, conserte e rode de novo até aparecer Fim.
#include <stdio.h>
int main(void) {
int i = 1;
do {
printf("%d\n", i);
i++;
} while (i <= 3)
printf("Fim\n");
return 0;
}
#include <stdio.h>
int main(void) {
int i = 1;
do {
printf("%d\n", i);
i++;
} while (i <= 3);
printf("Fim\n");
return 0;
}
do)
#include <stdio.h>
int main(void) {
do {
int nota = 0;
printf("Digite a nota (0 a 10): ");
scanf("%d", ¬a);
} while (nota < 0 || nota > 10);
return 0;
}
$ gcc -std=c23 -Wall -Wextra dentro.c -o dentro
dentro.c: In function ‘main’:
dentro.c:8:14: error: ‘nota’ undeclared (first use in this function)
8 | } while (nota < 0 || nota > 10);
| ^~~~
dentro.c:8:14: note: each undeclared identifier is reported only once for each function it appears in
O que significa: "‘nota’ não declarada (primeiro uso nesta função)". Uma variável criada dentro de { } só existe até a } que fecha o bloco (veja Escopo). A condição do while fica depois da }, onde nota já não existe. O Clang diz error: use of undeclared identifier 'nota'.
Como consertar: crie a variável antes do do: int nota = 0;, e dentro do laço só use (scanf("%d", ¬a);).
%c sem espaço)
if (scanf("%c", &resposta) != 1) {
$ ./continuar_errado Pedido 1 anotado. Deseja fazer outro pedido? (s/n) s Pedido 2 anotado. Deseja fazer outro pedido? (s/n) Total de pedidos: 2
O que aconteceu: a Ana digitou s e apertou Enter. O Enter também é um caractere ('\n') e ficou esperando na entrada. Na segunda pergunta, o %c leu esse '\n' na hora, sem esperar: como '\n' não é 's', o laço terminou. O compilador não tem como avisar: o programa é válido.
Como consertar: use " %c", com espaço antes do %. O espaço pula o Enter (e outros espaços) antes de ler a letra. Com %d isso não acontece porque o %d já pula espaços sozinho.
O que aconteceu: a condição do while nunca fica falsa. As causas mais comuns são: a variável testada não é a que o scanf preenche (while (escolha != 0) com scanf("%d", &opcao)); uma letra digitada sem conferir o retorno do scanf (o menu se repete mostrando a mesma opção antiga, como em while); ou a condição invertida (== no lugar de != faz o laço terminar logo, ao contrário).
Como parar: Ctrl+C no terminal, ou ■ Parar no editor do guia.
Referência
| Forma | O que faz |
|---|---|
do { … } while (condição); | Roda o corpo; depois testa. Repete enquanto a condição for verdadeira. Roda pelo menos 1 vez. Termina com ;. |
do { pergunta; } while (inválido); | Pedir de novo até a resposta ser válida. |
do { menu; switch …; } while (opcao != 0); | Menu que repete até a opção de sair. |
scanf(" %c", &r) | Lê uma letra pulando espaços e o Enter anterior. |
if (scanf("%d", &x) != 1) | Detecta quando a pessoa não digitou um número. |
Exercícios
1. O que falta?
Complete o fim do laço:
2. Condição da validação
Complete a condição para repetir enquanto a idade for menor que 0 ou maior que 120:
3. Quantas voltas?
Quantas vezes Oi aparece? int n = 50; do { printf("Oi\n"); n++; } while (n < 10);
4. Qual é a principal diferença entre while e do while?
5. Num programa com scanf("%c", &resposta) dentro de um do while, a segunda pergunta "Deseja continuar?" não espera a resposta. Qual é o conserto?
6. Qual destas tarefas pede um do while?
Missão final: o jogo de adivinhação
Missão: o número secreto é 7. Use um do while para pedir um palpite, contar a tentativa e dizer Mais alto! ou Mais baixo!, repetindo enquanto o palpite for diferente do segredo. No fim, mostre Acertou em N tentativas!. A entrada já traz os palpites 3, 9 e 7. (No projeto do jogo, o segredo é sorteado.)
#include <stdio.h>
int main(void) {
int segredo = 7;
int palpite = 0;
int tentativas = 0;
// escreva o do while aqui
printf("Acertou em %d tentativas!\n", tentativas);
return 0;
}
#include <stdio.h>
int main(void) {
int segredo = 7;
int palpite = 0;
int tentativas = 0;
do {
printf("Seu palpite: ");
if (scanf("%d", &palpite) != 1) {
return 1;
}
tentativas++;
if (palpite < segredo) {
printf("Mais alto!\n");
} else if (palpite > segredo) {
printf("Mais baixo!\n");
}
} while (palpite != segredo);
printf("Acertou em %d tentativas!\n", tentativas);
return 0;
}
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 gcc dizexpected ‘;’ before …. - Use
do whilepara validar entrada, menus e "deseja continuar?": a pergunta fica escrita uma vez só. - Variáveis usadas na condição nascem antes do
do; as criadas dentro das chaves não existem nowhile (…). - Confira o retorno do
scanfe use" %c"(com espaço) para ler uma letra depois de um Enter.