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.

Você vai aprender
  • A forma do do { … } while (condição); e por que o ; no fim é obrigatório.
  • A diferença prática entre while e do 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 %c importa.
  • 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 é:

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

whiledo while
Quando testa a condiçãoAntes de cada voltaDepois de cada volta
Menor número de voltas01
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.

Escreva o 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", &nota) != 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", &nota) != 1)
O scanf devolve quantos valores conseguiu ler. Se não for 1, a pessoa digitou algo que não é número. Aqui o programa avisa e termina com return 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ó.

Por que não tentar de novo quando a pessoa digita uma letra?

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", &nota) != 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", &nota) != 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, o break sai só do switch, não do laço. O programa continua até o while (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 %c manda o scanf pular espaços e quebras de linha antes de ler. Ele é essencial: sem ele, o scanf lê o Enter da resposta anterior (veja Quando dá errado).
resposta == 's' || resposta == 'S'
Aceita s minú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çãoLaçoPor quê
Menu, "deseja continuar?", pedir até ser válidodo whileA primeira volta é obrigatória: só dá para testar depois de perguntar.
Vender enquanto houver estoque, dobrar até passar de 1000whilePode 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 alunosforO 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

"expected ‘;’ before …" (esqueceu o ; 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;
}
"‘nota’ undeclared" (variável criada dentro do do)
#include <stdio.h>

int main(void) {
    do {
        int nota = 0;
        printf("Digite a nota (0 a 10): ");
        scanf("%d", &nota);
    } 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", &nota);).

O programa termina sem esperar a resposta (%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 menu volta sem parar

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

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

do { printf("Oi\n"); i++; } while (i < 3)

2. Condição da validação

Complete a condição para repetir enquanto a idade for menor que 0 ou maior que 120:

} while ();

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 diz expected ‘;’ before ….
  • Use do while para 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 no while (…).
  • Confira o retorno do scanf e use " %c" (com espaço) para ler uma letra depois de um Enter.