O laço que sempre executa uma vez
Um laço while testa antes de agir, então pode executar zero vezes. Isso normalmente está certo. Às vezes está exatamente errado: você não tem como saber se deve repetir um pedido antes de tê-lo exibido, e não tem como julgar a entrada do usuário antes de ter lido alguma. O do-while move o teste para o fim, então o corpo executa primeiro e a condição decide apenas se vai de novo.
A condição i < 5 é falsa desde o início. O laço while executa zero vezes; o do-while executa exatamente uma. Essa é toda a diferença entre os dois.
Sintaxe, e aquele ponto e vírgula
do {
/* corpo - sempre executa pelo menos uma vez */
} while (condicao);
A ordem se lê do jeito que executa: faça (do) o corpo, enquanto (while) a condição ainda valer, faça de novo.
O ponto e vírgula depois do parêntese de fechamento é obrigatório. do ... while (cond); é uma instrução, e instruções em C terminam em ponto e vírgula. Omita-o e o compilador continua lendo, depois relata um erro de sintaxe em algum ponto abaixo - por isso o erro real costuma estar várias linhas acima da linha apontada.
Este também é o único lugar em C onde while (cond); com ponto e vírgula está correto em vez de ser um bug. Em um laço while comum, a mesma pontuação cria um corpo vazio e normalmente um laço infinito; aqui ela está fechando um do.
As chaves são opcionais para um corpo de uma instrução só mas, como em toda outra estrutura de controle do C, escreva-as mesmo assim.
O padrão de validação de entrada
É para isto que o do-while foi projetado. Você precisa ler algo antes de poder dizer se é aceitável, então a leitura tem que acontecer antes do teste:
O laço continua lendo até um valor passar, e a mesma condição que rejeita um valor ruim é a que pede outra passagem. Escrita como um while, a leitura teria que aparecer duas vezes - uma antes do laço para preparar a condição, outra no fim do corpo - que é a duplicação que o do-while elimina.
Com entrada real, o corpo chamaria scanf:
int idade;
do {
printf("Digite sua idade (1-120): ");
if (scanf("%d", &idade) != 1) {
while (getchar() != '\n') { } /* descarta a linha ruim */
idade = -1; /* forca outra passagem */
}
} while (idade < 1 || idade > 120);
Note o while interno que esvazia o resto da linha. Se o scanf falha ao converter, o texto problemático continua no buffer de entrada e toda leitura posterior falha nele também - um laço que gira para sempre imprimindo o pedido. Limpá-lo faz parte do padrão.
O padrão de menu
O outro uso clássico: mostrar as opções, ler uma escolha, agir sobre ela e repetir até o usuário sair. O menu precisa aparecer antes de existir qualquer escolha a testar.
O break dentro do switch encerra o switch, não o laço - um ponto que vale precisar, já que os dois usam a mesma palavra-chave. Aqui o laço termina porque escolha != 4 se torna falso. Se você quisesse mesmo sair do laço de dentro do switch, return ou uma variável de flag seriam o caminho; o break sozinho não consegue.
Uma primeira passagem garantida pode ser um bug
Como o corpo executa antes de qualquer teste, o do-while processa alegremente dados que não existem:
/* BUG: imprime a[0] mesmo quando n e 0 */
int i = 0;
do {
printf("%d\n", a[i]);
i++;
} while (i < n);
Com n == 0 isso lê a[0] em um array vazio - comportamento indefinido. Qualquer laço sobre uma coleção que possa estar vazia quer um while ou um for, cujo teste vem primeiro.
A regra prática: use do-while só quando uma execução de zero iterações for impossível pela natureza do problema, não apenas improvável na prática. Pedir algo ao usuário, jogar dados até um alvo aparecer, gerar e testar um candidato - esses genuinamente não podem ser julgados antes da primeira passagem. Percorrer uma lista não pode alegar isso.
break e continue em um do-while
Os dois funcionam, e o continue tem uma peculiaridade que vale conhecer: ele salta para o teste da condição, não para o topo do corpo.
O i++ no topo do corpo executa em toda passagem, inclusive nas que o continue interrompe, então o laço continua avançando. Coloque a atualização depois de um continue e o laço trava - a mesma armadilha dos laços while.
O break sai do laço imediatamente e pula a condição por completo.
Escolhendo entre os três laços
Os três laços do C têm o mesmo poder; a escolha é sobre qual deles declara a intenção.
for um contador, seu limite e seu passo pertencem juntos - "n vezes"
while repete até uma condição mudar, e talvez nem uma vez - "até que"
do-while o mesmo, mas a primeira passagem e garantida - "pelo menos uma vez"
Na prática o do-while é de longe o mais raro dos três. A maioria dos laços ou conta ou precisa tratar o caso vazio, e ambos querem o teste no topo. Recorra ao do-while quando se pegar duplicando uma instrução logo antes de um laço while para preparar a condição dele - essa duplicação é o sinal.
Perguntas frequentes
Como se escreve um laço do-while em C?
do { corpo } while (condicao); - o corpo vem primeiro, o teste vem depois, e a instrução inteira termina com um ponto e vírgula. O corpo sempre executa pelo menos uma vez e depois se repete enquanto a condição for diferente de zero.
Qual é a diferença entre while e do-while em C?
Onde fica o teste. Um laço while verifica a condição antes da primeira passagem, então pode executar zero vezes. Um do-while verifica depois, então sempre executa pelo menos uma vez. Escolha do-while só quando essa primeira passagem garantida for genuinamente o que o problema exige.
Por que um laço do-while precisa de ponto e vírgula no fim?
Porque do ... while (cond); é uma única instrução e, como toda instrução em C, termina com ponto e vírgula. Omiti-lo produz um erro de sintaxe confuso apontando para a linha seguinte, já que o compilador continua lendo à procura do resto da instrução.
Quando devo usar um laço do-while?
Quando o corpo precisa executar antes de você ter como saber se deve repetir: exibir um menu antes de ler a escolha, pedir de novo até a entrada ser válida, ou gerar um valor e então testá-lo. Se a condição pode ser verificada de antemão, um laço while diz isso de forma mais direta.