C for
Na aula do while, todo laço com contador tinha três peças espalhadas: o início antes do laço (int i = 1;), a condição nos parênteses (i <= 5) e o passo no fim do corpo (i++). O for ("para") junta as três numa linha só. É o laço mais usado em C quando você sabe quantas voltas quer: de 1 a 10, cada aluno da turma, cada posição de um array.
- As três partes do
fore a ordem em que elas rodam. - Por que
for (int i = 0; …)é coisa do C99 e como era escrito antes. - Como contar para trás, de 2 em 2 e com qualquer passo.
- Como fazer um somatório e uma tabuada.
- O erro mais comum de todos os laços: o "um a mais" do
<=. - Outros erros com as mensagens reais do gcc.
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: "dê 10 voltas na quadra"
Um professor de educação física diz: "deem 10 voltas na quadra". Cada aluno faz, sem pensar, três coisas:
- Começa a contar do 1 (isso acontece uma vez só, antes da primeira volta).
- Antes de cada volta, confere: já passei de 10? Se não, corre mais uma.
- No fim de cada volta, soma um na contagem.
O for escreve exatamente isso, nessa ordem, entre os parênteses: for (começa; confere; soma). Olhando só a primeira linha, você já sabe quantas voltas o laço vai dar.
1. O primeiro for
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 5; i++) {
printf("Volta %d\n", i);
}
printf("Fim!\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra for1.c -o for1 $ ./for1 Volta 1 Volta 2 Volta 3 Volta 4 Volta 5 Fim!
- for
- A palavra-chave do laço: "para" (para
ide 1 até 5…). - int i = 1;
- 1ª parte, o início. Roda uma vez só, antes de tudo. Aqui cria o contador
ivalendo 1. - i <= 5;
- 2ª parte, a condição. Testada antes de cada volta, como no
while. Se for falsa, o laço termina. - i++
- 3ª parte, o passo. Roda no fim de cada volta, depois do corpo. Repare que não tem
;depois dele. - { … }
- O corpo, como em qualquer laço.
A ordem exata
As partes estão escritas lado a lado, mas não rodam da esquerda para a direita a cada volta. A ordem é esta:
| Passo | O que roda | i |
|---|---|---|
| 1 | int i = 1 (início, só desta vez) | 1 |
| 2 | i <= 5? sim → corpo: Volta 1 → passo i++ | 2 |
| 3 | i <= 5? sim → corpo: Volta 2 → passo i++ | 3 |
| … | … | … |
| 6 | i <= 5? sim → corpo: Volta 5 → passo i++ | 6 |
| 7 | i <= 5? não → sai do laço | 6 |
Este for faz exatamente o mesmo que este while da aula anterior:
while | for |
|---|---|
int i = 1;
while (i <= 5) {
printf("Volta %d\n", i);
i++;
} | for (int i = 1; i <= 5; i++) {
printf("Volta %d\n", i);
} |
A vantagem do for: as três peças ficam juntas no topo, então fica mais difícil esquecer o passo (o laço infinito do while) e mais fácil ver quantas voltas serão.
2. for (int i = …) é C99; antes, a variável vinha fora C99
Criar o contador dentro dos parênteses (for (int i = 1; …)) só passou a valer no C99. Muito código antigo, e muitos livros e cursos, ainda escrevem do jeito do C89: a variável é declarada antes do for, e os parênteses só dão o valor inicial:
#include <stdio.h>
int main(void) {
int i;
for (i = 1; i <= 5; i++) {
printf("Volta %d\n", i);
}
printf("Fim! i agora vale %d\n", i);
return 0;
}
$ gcc -std=c89 -Wall -Wextra for_antigo.c -o for_antigo $ ./for_antigo Volta 1 Volta 2 Volta 3 Volta 4 Volta 5 Fim! i agora vale 6
Se você pedir o padrão antigo (-std=c89) e usar a forma nova, o gcc recusa:
$ gcc -std=c89 -Wall -Wextra for1.c -o for1
for1.c: In function ‘main’:
for1.c:4:5: error: ‘for’ loop initial declarations are only allowed in C99 or C11 mode
4 | for (int i = 1; i <= 5; i++) {
| ^~~
for1.c:4:5: note: use option ‘-std=c99’, ‘-std=gnu99’, ‘-std=c11’ or ‘-std=gnu11’ to compile your code
"Declarações no início do laço for só são permitidas no modo C99 ou C11". A mensagem é antiga e cita só o C99 e o C11, mas vale para todos os padrões depois deles (C17, C23). Com o comando padrão do guia (-std=c23) e no editor, a forma nova funciona.
for (int i = 1; …) C99 | int i; for (i = 1; …) (C89) | |
|---|---|---|
Onde i existe | Só dentro do for | No resto da função, também depois do laço |
| Depois do laço | i não existe mais (erro se usar) | i guarda o valor que parou o laço (6) |
| Quando usar | Quase sempre: o contador não "vaza" para o resto do programa | Quando precisa saber, depois, em que valor o laço parou |
3. Contar para trás e mudar o passo
As três partes aceitam qualquer coisa que faça sentido. Para contar para trás: comece do maior, teste "maior ou igual" e use --:
#include <stdio.h>
int main(void) {
for (int s = 10; s >= 1; s--) {
printf("%d ", s);
}
printf("Feliz Ano Novo!\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra regressiva_for.c -o regressiva_for $ ./regressiva_for 10 9 8 7 6 5 4 3 2 1 Feliz Ano Novo!
Para andar de 2 em 2, troque o passo por n += 2 (veja Operadores de Atribuição). Começando do 0, saem os números pares:
#include <stdio.h>
int main(void) {
for (int n = 0; n <= 20; n += 2) {
printf("%d ", n);
}
printf("\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra pares.c -o pares $ ./pares 0 2 4 6 8 10 12 14 16 18 20
| Quero… | Escrevo | Resultado |
|---|---|---|
| De 1 a 10 | for (int i = 1; i <= 10; i++) | 1 2 3 … 10 |
| De 0 a 9 (10 voltas) | for (int i = 0; i < 10; i++) | 0 1 2 … 9 |
| De 10 a 1 | for (int i = 10; i >= 1; i--) | 10 9 … 1 |
| Pares de 0 a 20 | for (int i = 0; i <= 20; i += 2) | 0 2 4 … 20 |
| Ímpares de 1 a 19 | for (int i = 1; i < 20; i += 2) | 1 3 5 … 19 |
| Dobrando | for (int i = 1; i < 1000; i *= 2) | 1 2 4 … 512 |
Missão: mude o for para mostrar os múltiplos de 5, de 5 a 50: 5 10 15 … 50. Você vai mexer no início, na condição e no passo.
#include <stdio.h>
int main(void) {
for (int n = 0; n <= 20; n += 2) {
printf("%d ", n);
}
printf("\n");
return 0;
}
#include <stdio.h>
int main(void) {
for (int n = 5; n <= 50; n += 5) {
printf("%d ", n);
}
printf("\n");
return 0;
}
4. Somatório: o for com acumulador
A técnica do acumulador do while fica ainda mais curta com for. Agora quem escolhe até onde somar é a pessoa, com scanf:
#include <stdio.h>
int main(void) {
int n = 0;
printf("Somar de 1 até: ");
if (scanf("%d", &n) != 1) {
printf("Isso não é um número.\n");
return 1;
}
int soma = 0;
for (int i = 1; i <= n; i++) {
soma += i;
}
printf("1 + 2 + ... + %d = %d\n", n, soma);
return 0;
}
$ gcc -std=c23 -Wall -Wextra somatorio.c -o somatorio $ ./somatorio Somar de 1 até: 100 1 + 2 + ... + 100 = 5050 $ ./somatorio Somar de 1 até: 0 1 + 2 + ... + 0 = 0
- int soma = 0;
- O acumulador nasce fora do
for, valendo 0, para sobreviver entre as voltas e ser mostrado depois. - i <= n
- A condição usa uma variável: o número de voltas é decidido quando o programa roda.
- soma += i;
- A cada volta, o contador entra no total.
Com 0, a condição 1 <= 0 já começa falsa: o for, como o while, pode dar zero voltas.
Tabuada
O contador também pode entrar numa conta dentro do corpo. A tabuada do 7:
#include <stdio.h>
int main(void) {
int numero = 7;
for (int i = 1; i <= 10; i++) {
printf("%d x %2d = %2d\n", numero, i, numero * i);
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra tabuada.c -o tabuada $ ./tabuada 7 x 1 = 7 7 x 2 = 14 7 x 3 = 21 7 x 4 = 28 7 x 5 = 35 7 x 6 = 42 7 x 7 = 49 7 x 8 = 56 7 x 9 = 63 7 x 10 = 70
O %2d reserva 2 espaços para o número, alinhando a coluna (veja Formatos do printf). Para mostrar a tabuada do 1 ao 10 inteira, você precisa de um for dentro de outro: isso é a aula Laços Aninhados.
5. O erro do "um a mais"
É o erro de laço mais comum do mundo, e tem até nome em inglês: off-by-one ("errar por um"). A Ana quer mostrar as 5 voltas de uma corrida. Ela começou do 0, como muita gente faz em C, mas manteve o <=:
#include <stdio.h>
int main(void) {
printf("As 5 voltas da corrida:\n");
for (int volta = 0; volta <= 5; volta++) {
printf("Volta %d\n", volta);
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra umamais.c -o umamais $ ./umamais As 5 voltas da corrida: Volta 0 Volta 1 Volta 2 Volta 3 Volta 4 Volta 5
Seis voltas! De 0 até 5 há seis números. O compilador não avisa: para ele, o programa está certo. As duas formas corretas de dar N voltas são:
| Forma | Valores | Quando usar |
|---|---|---|
for (int i = 1; i <= N; i++) | 1, 2, …, N | Para mostrar números "humanos" (volta 1, aluno 1) |
for (int i = 0; i < N; i++) | 0, 1, …, N-1 | Para percorrer arrays, cujas posições começam em 0. É a forma mais comum em C. |
A regra para lembrar: começou do 0, use <; começou do 1, use <=. Misturar (0 com <=, ou 1 com <) dá uma volta a mais ou a menos. Nos arrays, a volta a mais é perigosa de verdade: ela acessa uma posição que não existe (veja a aula Arrays).
Missão: conserte o laço para mostrar exatamente Volta 1 até Volta 5.
#include <stdio.h>
int main(void) {
printf("As 5 voltas da corrida:\n");
for (int volta = 0; volta <= 5; volta++) {
printf("Volta %d\n", volta);
}
return 0;
}
#include <stdio.h>
int main(void) {
printf("As 5 voltas da corrida:\n");
for (int volta = 1; volta <= 5; volta++) {
printf("Volta %d\n", volta);
}
return 0;
}
Formas diferentes de escrever
Duas variáveis com a vírgula
O início e o passo aceitam várias coisas separadas por vírgula. Aqui i sobe e j desce ao mesmo tempo, até se cruzarem:
#include <stdio.h>
int main(void) {
for (int i = 1, j = 10; i < j; i++, j--) {
printf("i = %d, j = %d\n", i, j);
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra virgula.c -o virgula $ ./virgula i = 1, j = 10 i = 2, j = 9 i = 3, j = 8 i = 4, j = 7 i = 5, j = 6
É útil de vez em quando (inverter a ordem de um array, por exemplo). Não abuse: se o for não cabe numa linha legível, um while costuma ser mais claro.
Partes vazias e o for (;;)
Qualquer uma das três partes pode ficar vazia, mas os dois ; continuam lá. Sem início, a variável vem de antes (for (; i <= 5; i++)). Sem condição, ela conta como sempre verdadeira: for (;;) é um laço infinito, igual a while (1). Ele só sai com break (aula break e continue), Ctrl+C no terminal ou ■ Parar no editor.
i++ ou ++i no passo?
No passo do for, tanto faz: o valor da expressão não é usado, só o efeito de somar 1. i++ é o mais comum em C. A diferença entre os dois está em ++ e --.
Qual laço usar?
| Situação | Laço |
|---|---|
| Sei quantas voltas (de 1 a N, cada posição de um array) | for |
| Não sei quantas voltas (até digitar 0, até o saldo dobrar) | while |
| Pelo menos uma volta (menu, validar entrada) | do while |
Qualquer for pode ser reescrito como while e vice-versa. A escolha é sobre clareza: o for diz "vou contar"; o while diz "vou esperar algo acontecer".
Quando dá errado
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 3; i++) {
printf("%d\n", i);
}
printf("i terminou valendo %d\n", i);
return 0;
}
$ gcc -std=c23 -Wall -Wextra fora.c -o fora
fora.c: In function ‘main’:
fora.c:7:39: error: ‘i’ undeclared (first use in this function)
7 | printf("i terminou valendo %d\n", i);
| ^
fora.c:7:39: note: each undeclared identifier is reported only once for each function it appears in
O que significa: "‘i’ não declarada". Uma variável criada nos parênteses do for só existe dentro dele. Na linha 7, o laço já acabou e i não existe mais. O Clang do editor diz error: use of undeclared identifier 'i'.
Como consertar: se você precisa do valor depois do laço, declare antes, no estilo antigo: int i; for (i = 1; i <= 3; i++).
for ( … )
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 3; i++); {
printf("Olá!\n");
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra pv_for.c -o pv_for
pv_for.c: In function ‘main’:
pv_for.c:4:5: warning: this ‘for’ clause does not guard... [-Wmisleading-indentation]
4 | for (int i = 1; i <= 3; i++); {
| ^~~
pv_for.c:4:35: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘for’
4 | for (int i = 1; i <= 3; i++); {
| ^
$ ./pv_for
Olá!
O que aconteceu: o ; logo depois do ) é um corpo vazio. O for deu as 3 voltas sem fazer nada, e o bloco de baixo rodou uma vez, depois do laço. O gcc avisa que a indentação engana; o Clang do editor diz warning: for loop has empty body [-Wempty-body].
Como consertar: apague o ; entre o ) e a {.
#include <stdio.h>
int main(void) {
for (unsigned int i = 3; i >= 0; i--) {
printf("%u\n", i);
}
printf("Fogo!\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra semsinal.c -o semsinal
semsinal.c: In function ‘main’:
semsinal.c:4:32: warning: comparison of unsigned expression in ‘>= 0’ is always true [-Wtype-limits]
4 | for (unsigned int i = 3; i >= 0; i--) {
| ^~
$ ./semsinal
3
2
1
0
4294967295
4294967294
^C « o Fogo! nunca chega
O que significa: "a comparação de uma expressão sem sinal com >= 0 é sempre verdadeira". Um unsigned int não tem números negativos (veja Inteiros): quando i vale 0 e leva i--, ele "dá a volta" para o maior valor possível, 4294967295, e a contagem continua para sempre. Esse aviso vem do -Wextra: mais um motivo para nunca compilar sem ele. O Clang do editor não dá esse aviso com -Wall -Wextra; lá o programa só enche a tela até o limite de saída.
Como consertar: para contar para trás até 0, use int: for (int i = 3; i >= 0; i--).
O que aconteceu: o laço começa do 0 com <= (uma volta a mais, como em o erro do "um a mais") ou começa do 1 com < (uma volta a menos: for (int i = 1; i < 10; i++) para no 9).
Como investigar: faça a tabela da primeira e da última volta: qual o valor de i na primeira? E qual o último valor em que a condição ainda é verdadeira? Conte os números entre eles.
Referência
| Forma | O que faz |
|---|---|
for (início; condição; passo) { … } | Roda o início uma vez; antes de cada volta testa a condição; depois de cada volta roda o passo. |
for (int i = 0; i < N; i++) | N voltas, de 0 a N-1 (a forma clássica para arrays). C99 |
for (int i = 1; i <= N; i++) | N voltas, de 1 a N. |
for (int i = N; i >= 1; i--) | Contagem regressiva. |
for (int i = 0; i <= M; i += 2) | De 2 em 2. |
int i; for (i = 0; …) | Estilo C89: i continua existindo depois do laço. |
for (int i = 0, j = 9; i < j; i++, j--) | Duas variáveis com vírgula. |
for (;;) | Laço infinito (sai com break). |
Exercícios
1. Complete o for
Complete para mostrar de 1 a 10:
2. Contagem regressiva
Complete o passo para contar de 10 até 1:
3. Quantas voltas?
Quantas vezes o corpo de for (int i = 0; i <= 10; i++) roda?
4. Em que ordem rodam as partes de for (A; B; C) { D }?
5. O gcc dá error: ‘for’ loop initial declarations are only allowed in C99 or C11 mode. O que aconteceu?
6. Qual destes laços mostra exatamente 5 números?
Missão final: fatorial
Missão: o fatorial de um número (escrito 5!) é a multiplicação de 1 até ele: 5! = 1 × 2 × 3 × 4 × 5 = 120. Use um for para multiplicar fatorial por cada número de 1 até n. A entrada já traz o 5; a saída deve ter 5! = 120. Dica: o acumulador de uma multiplicação começa em 1, não em 0.
#include <stdio.h>
int main(void) {
int n = 0;
printf("Fatorial de: ");
if (scanf("%d", &n) != 1) {
return 1;
}
int fatorial = 1;
// escreva o for aqui
printf("%d! = %d\n", n, fatorial);
return 0;
}
#include <stdio.h>
int main(void) {
int n = 0;
printf("Fatorial de: ");
if (scanf("%d", &n) != 1) {
return 1;
}
int fatorial = 1;
for (int i = 1; i <= n; i++) {
fatorial *= i;
}
printf("%d! = %d\n", n, fatorial);
return 0;
}
Resumo
for (início; condição; passo) { corpo }junta as três peças de um laço com contador numa linha.- O início roda uma vez; a condição, antes de cada volta; o passo, depois de cada volta.
for (int i = 0; …)é do C99; no C89 a variável era declarada antes. Aicriada nos parênteses só existe dentro do laço.- Para trás:
i--com>=. De 2 em 2:i += 2. Contadores que descem até 0 devem serint, nãounsigned. - N voltas:
i = 0; i < Noui = 1; i <= N. Misturar dá o erro do "um a mais".