C++ for

Na aula 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 no while (i <= 5) e o passo lá no fim do corpo (i++). O for junta as três numa linha só. Ele é o laço mais usado do C++ quando você sabe quantas voltas quer: de 1 a 10, cada uma das 3 provas, os 30 alunos da turma.

Você vai aprender
  • A anatomia do for: for (início; condição; passo), e em que ordem cada parte roda.
  • Como contar para a frente, de 2 em 2 e para trás.
  • Como fazer uma tabuada e a média de notas com for.
  • O erro do "um a mais": quando usar <= e quando usar <.
  • Por que a variável criada no for não existe depois dele (e o erro real do compilador).
  • Quando usar for e quando usar while.

Os programas foram compilados com o g++ 15 na máquina fictícia da Ana, na pasta ~/cpp, com g++ -std=c++23 -Wall -Wextra arquivo.cpp -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 a mesma coisa sem pensar: começa a contar do 1, a cada volta soma 1 na cabeça e para quando chega ao 10. Três coisas, sempre as mesmas:

PeçaNa quadraNo for
Início"Começo na volta 1"int volta = 1
Condição"Continuo enquanto não passei da 10"volta <= 10
Passo"Terminei uma, conto mais uma"volta++

O for pede exatamente essas três coisas, nessa ordem, separadas por ponto e vírgula.


1. Anatomia do for

#include <iostream>

int main() {
    for (int i = 1; i <= 5; i++) {
        std::cout << "Volta " << i << '\n';
    }
    std::cout << "Fim!\n";
}
for
A palavra-chave do laço. Em inglês, "para": para i de 1 até 5…
int i = 1;
Início: cria o contador e dá o valor inicial. Roda uma única vez, antes de tudo.
i <= 5;
Condição: testada antes de cada volta, como no while. Se for falsa, o laço acaba.
i++
Passo: roda no fim de cada volta, depois do corpo. Repare que não leva ; depois dele: logo vem o ).
{ … }
O corpo: o que se repete. Aqui, só mostra a volta. Não tem i++ dentro: ele já está no cabeçalho.
$ g++ -std=c++23 -Wall -Wextra contar.cpp -o contar
$ ./contar
Volta 1
Volta 2
Volta 3
Volta 4
Volta 5
Fim!

A ordem em que as partes rodam

O cabeçalho é lido da esquerda para a direita, mas não roda nessa ordem. O passo, que está escrito antes do corpo, roda depois dele:

  1. Início (int i = 1), uma vez só.
  2. Condição (i <= 5)? Se for falsa, pula para depois da } e o laço acaba.
  3. Corpo (mostra Volta i).
  4. Passo (i++).
  5. Volta para o passo 2.

Por isso, o for acima é exatamente o mesmo que este while:

Com forCom while
for (int i = 1; i <= 5; i++) {
    std::cout << i;
}
int i = 1;
while (i <= 5) {
    std::cout << i;
    i++;
}

A vantagem do for é que as três peças ficam juntas, à vista. Fica muito mais difícil esquecer o passo e criar um laço infinito. (Há uma pequena diferença sobre onde o i existe, que você vai ver na seção 5.)

Missão: faça o for contar de 1 até 10. Depois troque o texto "Volta " por "Aluno " e veja que só o corpo muda, o cabeçalho continua igual.

#include <iostream>

int main() {
    for (int i = 1; i <= 5; i++) {
        std::cout << "Volta " << i << '\n';
    }
    std::cout << "Fim!\n";
}
#include <iostream>

int main() {
    for (int i = 1; i <= 10; i++) {
        std::cout << "Volta " << i << '\n';
    }
    std::cout << "Fim!\n";
}

2. Contar de 2 em 2 e para trás

Basta mudar o passo (e, às vezes, o início e a condição). Para os números pares de 0 a 10, o passo é i += 2 ("some 2 em i", veja Operadores de Atribuição):

#include <iostream>

int main() {
    for (int i = 0; i <= 10; i += 2) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}
$ g++ -std=c++23 -Wall -Wextra pares.cpp -o pares
$ ./pares
0 2 4 6 8 10 

Os números saem na mesma linha porque o corpo mostra um espaço (' ') em vez de pular linha. O '\n' depois do laço termina a linha uma vez só.

Para trás, comece do maior, use i-- e troque a condição para "maior ou igual a 1":

#include <iostream>

int main() {
    for (int i = 10; i >= 1; i--) {
        std::cout << i << ' ';
    }
    std::cout << "Já!\n";
}
$ g++ -std=c++23 -Wall -Wextra regressiva.cpp -o regressiva
$ ./regressiva
10 9 8 7 6 5 4 3 2 1 Já!
A condição precisa combinar com a direção do passo

Se o contador sobe (i++), a condição é do tipo i <= fim. Se ele desce (i--), é do tipo i >= fim. Misturar os dois (for (int i = 10; i >= 1; i++)) faz o i subir para sempre, sem nunca ficar menor que 1: o laço não termina até o número "estourar" o limite do int, o que já é comportamento indefinido.

Quero…CabeçalhoResultado
1 a 10for (int i = 1; i <= 10; i++)1 2 3 … 10
0 a 9 (10 voltas)for (int i = 0; i < 10; i++)0 1 2 … 9
Pares de 0 a 10for (int i = 0; i <= 10; i += 2)0 2 4 6 8 10
Ímpares de 1 a 9for (int i = 1; i < 10; i += 2)1 3 5 7 9
De 5 em 5 até 50for (int i = 5; i <= 50; i += 5)5 10 15 … 50
10 até 1for (int i = 10; i >= 1; i--)10 9 8 … 1

Missão: mostre os múltiplos de 3 de 0 até 30, na mesma linha, separados por espaço: 0 3 6 9 12 15 18 21 24 27 30. Mude só o cabeçalho do for.

#include <iostream>

int main() {
    for (int i = 0; i <= 10; i += 2) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}
#include <iostream>

int main() {
    for (int i = 0; i <= 30; i += 3) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}

3. Tabuada

Um clássico: a pessoa escolhe o número e o programa mostra a tabuada de 1 a 10. O contador i não serve só para contar: ele entra na conta (n * i).

#include <iostream>

int main() {
    int n = 0;
    std::cout << "Tabuada de qual número? ";
    std::cin >> n;
    for (int i = 1; i <= 10; i++) {
        std::cout << n << " x " << i << " = " << n * i << '\n';
    }
}
$ g++ -std=c++23 -Wall -Wextra tabuada.cpp -o tabuada
$ ./tabuada
Tabuada de qual número? 7
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

Repare: n fica igual o tempo todo (7), e i muda a cada volta (1, 2, 3…). A tabuada completa, do 1 ao 10, precisa de um for dentro de outro: isso é a aula Laços Aninhados.

Repetir uma leitura N vezes: a média das provas

O for também serve para "faça isto 3 vezes". A Ana fez 3 provas e quer a média:

#include <iostream>

int main() {
    double soma = 0.0;
    for (int prova = 1; prova <= 3; prova++) {
        double nota = 0.0;
        std::cout << "Nota da prova " << prova << ": ";
        std::cin >> nota;
        soma += nota;
    }
    std::cout << "Média: " << soma / 3 << '\n';
}
$ g++ -std=c++23 -Wall -Wextra media.cpp -o media
$ ./media
Nota da prova 1: 7.5
Nota da prova 2: 9
Nota da prova 3: 6
Média: 7.5
  • O contador se chama prova: um nome que diz o que ele conta deixa o código mais fácil de ler que i.
  • nota nasce dentro do corpo, porque só é usada naquela volta; soma nasce fora, porque precisa sobreviver às 3 voltas (o acumulador da aula while).
  • soma é double, então soma / 3 é uma divisão com vírgula (veja Operadores Aritméticos).

4. O erro do "um a mais": <= × <

O erro mais famoso dos laços tem até nome em inglês: off-by-one, "errar por um". O laço dá uma volta a mais (ou a menos) do que você queria. Quase sempre o culpado é a troca entre <= e <:

#include <iostream>

int main() {
    std::cout << "Com <= : ";
    for (int i = 0; i <= 5; i++) {
        std::cout << i << ' ';
    }
    std::cout << '\n';

    std::cout << "Com <  : ";
    for (int i = 0; i < 5; i++) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}
$ g++ -std=c++23 -Wall -Wextra umamais.cpp -o umamais
$ ./umamais
Com <= : 0 1 2 3 4 5
Com <  : 0 1 2 3 4 

Começando do 0, i <= 5 dá 6 voltas (0 a 5), e i < 5 dá 5 voltas (0 a 4). Para não se confundir, escolha um dos dois "jeitos" e use sempre:

JeitoCabeçalho para N voltasValores de iQuando usar
Contar como gentefor (int i = 1; i <= N; i++)1, 2, …, NQuando o número aparece na tela: "Prova 1", "7 x 1"
Contar como o C++for (int i = 0; i < N; i++)0, 1, …, N−1Para percorrer listas, cujas posições começam do 0

O segundo jeito, começar do 0 e usar <, é o mais comum em C++, e você vai entender o porquê em Arrays: as posições de uma lista de 5 itens são 0, 1, 2, 3 e 4. Ali, o erro do "um a mais" deixa de ser só um número a mais na tela: o programa tenta ler uma posição que não existe, o que é um erro grave.

Teste rápido: conte as voltas

Em for (int i = A; i < B; i++), o número de voltas é B − A. Em for (int i = A; i <= B; i++), é B − A + 1. Quer 10 voltas a partir do 0? i < 10. A partir do 1? i <= 10.


5. A variável do for só existe dentro dele

Quando você cria o contador no cabeçalho (for (int i = 1; …)), ele pertence ao laço: nasce no início e desaparece quando o laço termina. Tentar usá-lo depois dá erro de compilação:

#include <iostream>

int main() {
    for (int i = 1; i <= 3; i++) {
        std::cout << i << '\n';
    }
    std::cout << "No fim, i vale " << i << '\n';
}
$ g++ -std=c++23 -Wall -Wextra escopo.cpp -o escopo
escopo.cpp: In function ‘int main()’:
escopo.cpp:7:39: error: ‘i’ was not declared in this scope
    7 |     std::cout << "No fim, i vale " << i << '\n';
      |                                       ^

"i não foi declarada neste escopo". O escopo de uma variável é o trecho do código onde ela existe (veja Escopo). O escopo do i criado no for é o próprio for: o cabeçalho e o corpo. A linha 7 já está fora dele. No editor do guia, o Clang diz error: use of undeclared identifier 'i'.

Isso é uma vantagem: você pode ter vários for seguidos, todos com i, sem um atrapalhar o outro (como no programa umamais.cpp acima). Se você precisa do valor depois do laço, crie a variável antes e deixe o início do for vazio:

#include <iostream>

int main() {
    int i = 1;
    for (; i <= 3; i++) {
        std::cout << i << '\n';
    }
    std::cout << "No fim, i vale " << i << '\n';
}
$ g++ -std=c++23 -Wall -Wextra escopo2.cpp -o escopo2
$ ./escopo2
1
2
3
No fim, i vale 4

O ; logo depois do ( continua obrigatório: ele marca que o início está vazio. Quando o for fica assim, muita gente prefere usar um while, que expressa a mesma coisa de um jeito mais natural.

Missão (provoque o erro): depois do laço, acrescente uma linha que mostra o valor de volta, por exemplo std::cout << volta << '\n';. Rode e leia a mensagem do compilador. Depois conserte, criando volta antes do for.

#include <iostream>

int main() {
    for (int volta = 1; volta <= 3; volta++) {
        std::cout << "Volta " << volta << '\n';
    }
}
#include <iostream>

int main() {
    for (int volta = 1; volta <= 3; volta++) {
        std::cout << "Volta " << volta << '\n';
    }
    std::cout << volta << '\n';
}

Formas diferentes de escrever

Partes vazias e o for (;;)

Qualquer uma das três partes pode ficar vazia; os dois ; continuam. Sem condição, ela é considerada sempre verdadeira, e for (;;) vira um laço infinito, igual a while (true). Ele precisa de um break lá dentro para terminar (veja break e continue).

Duas variáveis no mesmo for

No início e no passo, uma vírgula separa várias coisas do mesmo tipo. Aqui, i sobe e j desce até se encontrarem:

#include <iostream>

int main() {
    for (int i = 1, j = 10; i < j; i++, j--) {
        std::cout << i << " e " << j << '\n';
    }
}
$ g++ -std=c++23 -Wall -Wextra dois.cpp -o dois
$ ./dois
1 e 10
2 e 9
3 e 8
4 e 7
5 e 6

É útil de vez em quando, mas deixa o cabeçalho pesado. Na dúvida, prefira um contador só.

i++ ou ++i?

No passo do for, tanto faz: o valor que o ++ devolve é jogado fora, só importa que i aumentou. Você vai ver muito ++i em código C++ profissional, um costume que vem dos iteradores. Para números, use o que achar mais legível (a diferença está em ++ e --).

for ou while?

SituaçãoUse
Sei o número de voltas, ou ele está numa variável (n, o tamanho da lista)for
Tenho um contador com início, fim e passo clarosfor
Repito até algo acontecer (usuário digitar 0, saldo dobrar)while
O corpo precisa rodar ao menos uma vezdo-while
Passar por todos os itens de uma lista, sem precisar da posiçãofor de intervalo

Quando dá errado

Vírgulas no lugar dos pontos e vírgulas
#include <iostream>

int main() {
    for (int i = 0, i < 3, i++) {
        std::cout << i << '\n';
    }
}
$ g++ -std=c++23 -Wall -Wextra virgula.cpp -o virgula
virgula.cpp: In function ‘int main()’:
virgula.cpp:4:22: error: expected ‘;’ before ‘<’ token
    4 |     for (int i = 0, i < 3, i++) {
      |                      ^~
      |                      ;
virgula.cpp:4:23: error: expected primary-expression before ‘<’ token
    4 |     for (int i = 0, i < 3, i++) {
      |                       ^
virgula.cpp:4:31: error: expected ‘;’ before ‘)’ token
    4 |     for (int i = 0, i < 3, i++) {
      |                               ^
      |                               ;

O que significa: "esperava ; antes do <". Depois de int i = 0, o compilador achou que você ia criar outra variável (como em int i = 0, j = 10) e se perdeu no <. Os erros seguintes são consequência do primeiro: conserte sempre o primeiro erro e compile de novo (veja Lendo Erros do Compilador).

Como consertar: as três partes são separadas por ponto e vírgula: for (int i = 0; i < 3; i++).

O corpo roda uma vez só (ponto e vírgula depois do ))
#include <iostream>

int main() {
    for (int i = 1; i <= 3; i++); {
        std::cout << "Olá\n";
    }
}
$ g++ -std=c++23 -Wall -Wextra pontovirgula.cpp -o pontovirgula
pontovirgula.cpp: In function ‘int main()’:
pontovirgula.cpp:4:5: warning: this ‘for’ clause does not guard... [-Wmisleading-indentation]
    4 |     for (int i = 1; i <= 3; i++); {
      |     ^~~
pontovirgula.cpp: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++); {
      |                                   ^
$ ./pontovirgula
Olá

O que significa: o ; logo depois do ) é um corpo vazio. O laço deu suas 3 voltas sem fazer nada, e o bloco { … } de baixo rodou uma vez, depois do laço. No while, o mesmo erro trava o programa; no for, como o passo está no cabeçalho, o laço termina, e o erro passa despercebido se você não ler o aviso. O Clang do editor avisa: warning: for loop has empty body [-Wempty-body].

Como consertar: apague o ; entre o ) e a {.

"‘i’ was not declared in this scope" depois do laço

O que aconteceu: a variável criada no cabeçalho do for só existe dentro dele (seção 5).

Como consertar: se precisar do valor depois do laço, crie a variável antes do for.

Uma volta a mais ou a menos

O que aconteceu: a combinação de início e condição não dá o número de voltas que você queria (seção 4). O compilador não tem como saber o que você queria, então não avisa.

Como investigar: mostre o i em cada volta e confira o primeiro e o último valor. Use a regra: do 0 com < N, ou do 1 com <= N.


Referência

FormaO que faz
for (início; condição; passo) { … }Início uma vez; depois: testa, corpo, passo, testa…
for (int i = 0; i < n; i++)n voltas, i de 0 a n−1 (o padrão para listas).
for (int i = 1; i <= n; i++)n voltas, i de 1 a n.
for (int i = n; i >= 1; i--)Para trás, de n a 1.
for (int i = 0; i <= 10; i += 2)De 2 em 2.
for (; cond; passo)Sem início (a variável foi criada antes).
for (;;)Infinito; sai com break.
for (int i = 0, j = 9; i < j; i++, j--)Duas variáveis.

Exercícios

1. Complete o cabeçalho

Complete para mostrar de 1 a 20:

for (int i = 1; ; i++)

2. O passo

Complete o passo para mostrar 0 5 10 15 20:

for (int i = 0; i <= 20; )

3. Quantas voltas?

Quantas vezes o corpo de for (int i = 0; i <= 10; i++) roda?

4. Em que ordem as partes de for (A; B; C) { D } rodam?

5. Qual cabeçalho mostra 5 4 3 2 1?

6. Depois de for (int i = 0; i < 3; i++) { }, a linha std::cout << i;…

Missão final: a tabuada do 9

Missão: com um for, mostre a tabuada do 9, de 9 x 1 = 9 até 9 x 10 = 90, uma conta por linha, no mesmo formato da tabuada da aula.

#include <iostream>

int main() {
    int n = 9;
    // escreva o for aqui

}
#include <iostream>

int main() {
    int n = 9;
    for (int i = 1; i <= 10; i++) {
        std::cout << n << " x " << i << " = " << n * i << '\n';
    }
}

Resumo

  • for (início; condição; passo) { corpo } junta as três peças de um laço com contador numa linha.
  • Ordem: início (uma vez) → condição → corpo → passo → condição → …
  • O passo pode ser i++, i--, i += 2…; a condição tem de combinar com a direção.
  • "Um a mais": do 0 com < N ou do 1 com <= N dão N voltas. Para listas, use do 0 com <.
  • A variável criada no cabeçalho só existe dentro do for; usá-la depois dá ‘i’ was not declared in this scope.
  • Separe as partes com ; (não vírgula) e não ponha ; depois do ).
  • Sabe quantas voltas? for. Repete até algo acontecer? while.