Um computador não se cansa. É essa, no fundo, a razão de existir da programação: mandar a máquina repetir uma tarefa mil, um milhão, um bilhão de vezes sem reclamar. Os laços são a ferramenta que dá acesso a esse poder. O C oferece três, e cada um brilha em uma situação. Hoje você vai aprender a escolher o certo — e a nunca deixar um laço rodar para sempre por acidente.
O laço while
O while repete um bloco enquanto uma condição for verdadeira. Ele testa antes de cada repetição:
#include <stdio.h>
int main(void) {
int contador = 1;
while (contador <= 5) {
printf("Contagem: %d\n", contador);
contador++; // sem isto, o laço nunca termina!
}
return 0;
}
Três ingredientes são obrigatórios em todo laço, e o esquecimento de qualquer um causa bugs: uma inicialização (contador = 1), uma condição de parada (contador <= 5) e uma atualização que aproxima o laço do fim (contador++). Esqueça o contador++ e você terá um laço infinito — o programa imprime "Contagem: 1" para sempre.
O laço do-while: pelo menos uma vez
O do-while é irmão do while, com uma diferença crucial: ele testa a condição depois de executar o bloco. Portanto, o corpo roda ao menos uma vez, aconteça o que acontecer:
#include <stdio.h>
int main(void) {
int numero;
do {
printf("Digite um número positivo: ");
scanf("%d", &numero);
} while (numero <= 0);
printf("Obrigado! Você digitou %d.\n", numero);
return 0;
}
Esse é o caso de uso clássico: pedir uma entrada ao usuário e repetir enquanto ela for inválida. Faz sentido perguntar pelo menos uma vez antes de checar. Note o ponto e vírgula ao fim do while(...) — no do-while, ele é obrigatório.
O laço for: quando você sabe quantas vezes
O for reúne os três ingredientes — inicialização, condição e atualização — em uma única linha, o que o torna o laço ideal quando você conhece o número de repetições:
#include <stdio.h>
int main(void) {
for (int i = 0; i < 5; i++) {
printf("i = %d\n", i);
}
return 0;
}
A estrutura é for (inicialização; condição; atualização). Ela executa nesta ordem: inicializa i uma vez; testa a condição; se verdadeira, roda o corpo; executa a atualização; testa de novo; e assim por diante. Repare que declaramos i dentro do for — assim ele existe só durante o laço, respeitando o princípio do escopo mínimo que vimos no artigo sobre funções.
Por convenção histórica, contadores de laço em C começam em 0 e usam < (não <=). Isso não é capricho: mais tarde, ao percorrer vetores, essa contagem "de 0 a n−1" vai casar exatamente com a forma como os índices funcionam.
Qual laço usar?
A regra prática: use for quando souber o número de repetições (percorrer um vetor, contar de 1 a 100); use while quando repetir até uma condição incerta (ler um arquivo até o fim, esperar um evento); use do-while quando precisar garantir ao menos uma execução (menus, validação de entrada). Os três são intercambiáveis na teoria — qualquer um pode simular os outros —, mas escolher o certo torna a intenção do código óbvia para quem lê.
Interrompendo e pulando: break e continue
Duas palavras dão controle fino sobre o laço. O break abandona o laço imediatamente:
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 100; i++) {
if (i * i > 50) {
printf("O primeiro quadrado acima de 50 é %d² = %d\n", i, i * i);
break; // achou, não precisa continuar
}
}
return 0;
}
O continue pula para a próxima repetição, ignorando o resto do corpo:
#include <stdio.h>
int main(void) {
// imprime apenas os ímpares de 1 a 10
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // é par: pula para o próximo i
}
printf("%d ", i);
}
printf("\n");
return 0;
}
Saída: 1 3 5 7 9
Laços aninhados
Um laço pode viver dentro de outro. É assim que se percorrem tabelas, matrizes e grades:
#include <stdio.h>
int main(void) {
for (int linha = 1; linha <= 3; linha++) {
for (int col = 1; col <= 3; col++) {
printf("%d ", linha * col);
}
printf("\n"); // quebra de linha ao fim de cada linha
}
return 0;
}
Saída (uma tabuada 3×3):
1 2 3
2 4 6
3 6 9
O laço interno completa todas as suas voltas para cada volta do externo. Cuidado com o custo: dois laços de mil voltas cada resultam em um milhão de repetições. Essa noção é a semente do que, mais tarde, chamaremos de complexidade de algoritmos.
Um programa completo
#include <stdio.h>
int main(void) {
int n = 10;
long soma = 0;
long fatorial = 1;
for (int i = 1; i <= n; i++) {
soma += i; // acumula a soma
fatorial *= i; // acumula o produto
}
printf("Soma de 1 a %d: %ld\n", n, soma);
printf("%d! = %ld\n", n, fatorial);
return 0;
}
Saída:
Soma de 1 a 10: 55
10! = 3628800
Repare no padrão de acumulador: uma variável começa num valor neutro (0 para soma, 1 para produto) e é atualizada a cada volta. Esse padrão aparece em toda parte na programação — some, conte, encontre o maior, junte texto.
O que vem a seguir
Com decisões e repetições, você já tem uma linguagem Turing-completa nas mãos: em teoria, qualquer programa pode ser escrito só com o que vimos até aqui. Mas falta guardar coleções de dados. No próximo artigo, vamos aos vetores — e será nosso primeiro encontro real com a memória disposta em sequência. É também a porta de entrada para o tema mais importante e temido do C: os ponteiros.
Fontes e leituras recomendadas
- The C Programming Language (K&R), Kernighan & Ritchie — Cap. 3, Control Flow (laços)
- cppreference —
forloop — https://en.cppreference.com/w/c/language/for - cppreference —
whileedo-while— https://en.cppreference.com/w/c/language/while - cppreference —
breakecontinue— https://en.cppreference.com/w/c/language/break - Modern C, Jens Gustedt — seção sobre iteração — https://gustedt.gitlabpages.inria.fr/modern-c/
Exercícios
Exercício 1
Escreva um for que imprima os números de 10 até 1, em ordem decrescente.
Ver resposta
✓ Resposta: Basta inverter a inicialização, a condição e a atualização:
for (int i = 10; i >= 1; i--) {
printf("%d\n", i);
}
Exercício 2
Usando while, calcule e imprima a soma de todos os números pares de 1 a 100.
Ver resposta
✓ Resposta:
#include <stdio.h>
int main(void) {
int i = 2;
int soma = 0;
while (i <= 100) {
soma += i;
i += 2; // salta de 2 em 2, só nos pares
}
printf("Soma dos pares: %d\n", soma); // 2550
return 0;
}
Exercício 3
Converta este for em um while equivalente, produzindo a mesma saída: for (int i = 0; i < 5; i++) printf("%d\n", i);
Ver resposta
✓ Resposta: O while precisa reproduzir os três ingredientes separadamente:
int i = 0; // inicialização
while (i < 5) { // condição
printf("%d\n", i);
i++; // atualização
}
Isso mostra que o for é, na prática, um while mais compacto.
Exercício 4
Escreva um laço que imprima a tabuada do 7 (de 7×1 a 7×10), uma multiplicação por linha, no formato 7 x 1 = 7.
Ver resposta
✓ Resposta:
for (int i = 1; i <= 10; i++) {
printf("7 x %d = %d\n", i, 7 * i);
}
Exercício 5
Usando dois laços aninhados, imprima um triângulo de asteriscos com 5 linhas, onde a primeira linha tem 1 asterisco e a última tem 5.
Ver resposta
✓ Resposta: O laço interno usa o contador do externo como limite:
#include <stdio.h>
int main(void) {
for (int linha = 1; linha <= 5; linha++) {
for (int a = 1; a <= linha; a++) {
printf("*");
}
printf("\n");
}
return 0;
}
Saída:
*
**
***
****
*****
Como o limite do laço interno (a <= linha) cresce a cada volta do externo, cada linha ganha um asterisco a mais.