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.

Você vai aprender
  • As três partes do for e 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:

  1. Começa a contar do 1 (isso acontece uma vez só, antes da primeira volta).
  2. Antes de cada volta, confere: já passei de 10? Se não, corre mais uma.
  3. 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 i de 1 até 5…).
int i = 1;
1ª parte, o início. Roda uma vez só, antes de tudo. Aqui cria o contador i valendo 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:

PassoO que rodai
1int i = 1 (início, só desta vez)1
2i <= 5? sim → corpo: Volta 1 → passo i++2
3i <= 5? sim → corpo: Volta 2 → passo i++3
………
6i <= 5? sim → corpo: Volta 5 → passo i++6
7i <= 5? não → sai do laço6

Este for faz exatamente o mesmo que este while da aula anterior:

whilefor
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; …) C99int i; for (i = 1; …) (C89)
Onde i existeSó dentro do forNo resto da função, também depois do laço
Depois do laçoi não existe mais (erro se usar)i guarda o valor que parou o laço (6)
Quando usarQuase sempre: o contador não "vaza" para o resto do programaQuando 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…EscrevoResultado
De 1 a 10for (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 1for (int i = 10; i >= 1; i--)10 9 … 1
Pares de 0 a 20for (int i = 0; i <= 20; i += 2)0 2 4 … 20
Ímpares de 1 a 19for (int i = 1; i < 20; i += 2)1 3 5 … 19
Dobrandofor (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:

FormaValoresQuando usar
for (int i = 1; i <= N; i++)1, 2, …, NPara mostrar números "humanos" (volta 1, aluno 1)
for (int i = 0; i < N; i++)0, 1, …, N-1Para 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çãoLaç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

"‘i’ undeclared" depois do laço
#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++).

Um ponto e vírgula depois do 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 {.

"comparison of unsigned expression in ‘>= 0’ is always true"
#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--).

Uma volta a mais ou a menos

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

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

for (int i = 1; ; i++) { printf("%d\n", i); }

2. Contagem regressiva

Complete o passo para contar de 10 até 1:

for (int i = 10; i >= 1; ) { printf("%d\n", i); }

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. A i criada 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 ser int, não unsigned.
  • N voltas: i = 0; i < N ou i = 1; i <= N. Misturar dá o erro do "um a mais".