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.
- 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
fornão existe depois dele (e o erro real do compilador). - Quando usar
fore quando usarwhile.
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ça | Na quadra | No 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:
- Início (
int i = 1), uma vez só. - Condição (
i <= 5)? Se for falsa, pula para depois da}e o laço acaba. - Corpo (mostra
Volta i). - Passo (
i++). - Volta para o passo 2.
Por isso, o for acima é exatamente o mesmo que este while:
Com for | Com 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á!
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çalho | Resultado |
|---|---|---|
| 1 a 10 | for (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 10 | for (int i = 0; i <= 10; i += 2) | 0 2 4 6 8 10 |
| Ímpares de 1 a 9 | for (int i = 1; i < 10; i += 2) | 1 3 5 7 9 |
| De 5 em 5 até 50 | for (int i = 5; i <= 50; i += 5) | 5 10 15 … 50 |
| 10 até 1 | for (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 quei. notanasce dentro do corpo, porque só é usada naquela volta;somanasce fora, porque precisa sobreviver às 3 voltas (o acumulador da aula while).somaédouble, entãosoma / 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:
| Jeito | Cabeçalho para N voltas | Valores de i | Quando usar |
|---|---|---|---|
| Contar como gente | for (int i = 1; i <= N; i++) | 1, 2, …, N | Quando 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−1 | Para 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.
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ção | Use |
|---|---|
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 claros | for |
| Repito até algo acontecer (usuário digitar 0, saldo dobrar) | while |
| O corpo precisa rodar ao menos uma vez | do-while |
| Passar por todos os itens de uma lista, sem precisar da posição | for de intervalo |
Quando dá errado
#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++).
))
#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 {.
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.
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
| Forma | O 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:
2. O passo
Complete o passo para mostrar 0 5 10 15 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
< Nou do 1 com<= Ndã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.