Um laço for repete um bloco enquanto uma condição for verdadeira, com a preparação e o passo escritos no cabeçalho do laço. É o laço para quando você conta: um número fixo de repetições, ou cada índice de um array.
Saída:
Lap 1 of 5
Lap 2 of 5
Lap 3 of 5
Lap 4 of 5
Lap 5 of 5
Como as três partes executam
for (initializer; condition; iterator) executa em uma ordem fixa:
- O inicializador (
int i = 1) executa uma vez, antes de tudo. - A condição (
i <= 5) é verificada. Se for falsa, o laço termina e o corpo não executa mais. - O corpo executa.
- O iterador (
i++) executa, e o controle volta ao passo 2.
Como a condição é verificada antes de cada iteração, um laço for pode executar zero vezes: for (int i = 10; i < 5; i++) nunca entra no corpo. O laço acima se comporta como este laço while:
int i = 1;
while (i <= 5)
{
Console.WriteLine($"Lap {i} of 5");
i++;
}
As duas formas diferem em um detalhe: continue dentro do corpo de um for ainda executa o iterador, enquanto nesta versão com while ele pularia o i++, então o laço testaria o mesmo i de novo e poderia girar para sempre. Uma variável declarada no inicializador só existe dentro do laço. Se você precisa do valor final depois, declare-a antes do laço: int i; for (i = 0; ...; i++) { }.
Contagem regressiva e passos
O iterador pode ser qualquer expressão. Decremente para contar para baixo, some mais de um para avançar em passos, ou multiplique para uma sequência geométrica:
Saída:
3... 2... 1... liftoff
00 15 30 45
1 10 100 1000
Garanta que o iterador leve a condição a ficar falsa. for (int i = 0; i < 10; i--) se afasta de 10 e só para quando i dá a volta depois de dois bilhões de iterações.
Percorrendo um array por índice
Arrays expõem Length, listas expõem Count, e os índices válidos vão de 0 até um a menos que isso. O índice dá algo que o foreach não dá: acesso à posição, aos vizinhos e o direito de escrever de volta.
Saída:
#1: 17.99
#2: 4.50
#3: 38.25
#4: 7.43
item 1 vs item 0: down
item 2 vs item 1: up
item 3 vs item 2: down
O último laço começa em 1 porque compara cada elemento com o anterior. A página de arrays cobre como criar, ordenar e copiar os próprios arrays.
Várias variáveis de controle
O inicializador pode declarar várias variáveis do mesmo tipo, e o iterador pode atualizar várias, separadas por vírgulas. O uso clássico são dois índices andando um em direção ao outro:
Saída:
racecar is a palindrome: True
9, 1, 8, 3
As duas variáveis precisam ter o mesmo tipo em uma única declaração: int left = 0, right = 10 funciona, int i = 0, string s = "" não.
Laços aninhados
Um laço dentro de outro percorre todo o seu intervalo uma vez por iteração do laço externo. Tabelas e grades são o caso típico:
Saída:
1 2 3 4
2 4 6 8
3 6 9 12
4 8 12 16
O corpo interno executa 16 vezes (4 × 4). Aninhar multiplica o trabalho rapidamente: dois laços aninhados sobre 10.000 itens cada são 100 milhões de iterações. Um break no laço interno sai só do laço interno; a página de break e continue mostra como sair dos dois.
Laços infinitos: for(;;)
As três partes do cabeçalho são opcionais. Sem condição, o laço executa até que algo dentro dele saia:
Saída:
Month 1: 70 left
Month 2: 40 left
Month 3: 10 left
Overdrawn in month 4: -20
for (;;) e while (true) compilam para a mesma coisa; escolha o que o seu código já usa.
Erros off by one
O bug mais comum em um for é uma condição que vai um passo longe demais:
Saída:
Ada
Grace
Linus
IndexOutOfRangeException at index 3
Um array de 3 elementos tem os índices 0, 1 e 2, então i < names.Length é a condição certa. O bug espelhado é contar para baixo com i > 0, que nunca visita o índice 0. Em uma List<T>, o mesmo erro lança ArgumentOutOfRangeException no lugar.
Removendo itens durante o laço
Remover de uma List<T> dentro de um laço para frente desloca todos os elementos seguintes uma posição para baixo, então o laço pula o elemento logo depois de cada remoção:
Saída:
forward: 5, 0, 3, 7
backward: 5, 3, 7
O laço para frente deixou um 0 para trás: depois de remover o índice 1, o segundo zero passou para o índice 1, mas o i++ já tinha avançado para o índice 2. Percorrer de trás para frente evita isso porque as remoções só deslocam elementos que você já visitou. Como alternativa de uma linha, stock.RemoveAll(x => x == 0) faz a mesma coisa. Um laço foreach não permite remoção nenhuma; ele lança InvalidOperationException.
Contadores de ponto flutuante
Evite contadores double que testam igualdade. 0.1 não tem representação binária exata, então somá-lo dez vezes não produz exatamente 1.0:
for (double x = 0; x != 1.0; x += 0.1) // never ends: x skips past 1.0
{
}
Conte com um inteiro e calcule o valor a partir dele: for (int i = 0; i <= 10; i++) { double x = i / 10.0; }.
for versus foreach
| Necessidade | Use |
|---|---|
| Ler todos os elementos em ordem | foreach |
O índice, ou os vizinhos (i - 1, i + 1) | for |
| Atribuir a um elemento do array | for |
| Avançar de 2 em 2, ir de trás para frente | for |
Remover de uma List durante o laço | for, de trás para frente |
Uma coleção sem indexador (HashSet, Dictionary, resultados de LINQ) | foreach |
| Repetir algo N vezes, sem coleção | for |
Em arrays, os dois laços compilam para praticamente o mesmo código, então escolha pela legibilidade, não pela velocidade.
Perguntas frequentes
Qual é a sintaxe de um laço for em C#?
for (initializer; condition; iterator) { body }, por exemplo for (int i = 0; i < 5; i++) { ... }. O inicializador executa uma vez, a condição é verificada antes de cada iteração e o iterador executa depois de cada iteração. O laço termina na primeira vez em que a condição é falsa.
Como percorrer de trás para frente em C#?
Comece no último índice e decremente: for (int i = items.Length - 1; i >= 0; i--). Repare no >= 0, não > 0, senão o primeiro elemento é pulado. Percorrer de trás para frente também é a forma segura de remover itens de uma List durante a iteração.
Quando usar for em vez de foreach em C#?
Use for quando você precisa do índice (para comparar vizinhos, escrever de volta em um array ou avançar mais de um por vez), quando você conta em vez de percorrer uma coleção, ou quando remove itens de uma lista. Use foreach para ler todos os elementos em ordem; é mais curto e não tem índice para errar.
Como escrever um laço infinito em C#?
for (;;) { ... } ou while (true) { ... }. As três partes do cabeçalho de um for são opcionais, e uma condição ausente conta como verdadeira. Saia do laço com break ou return quando a condição de saída for atendida.
Por que recebo IndexOutOfRangeException no meu laço for?
A condição deixa o índice chegar ao tamanho: i <= array.Length visita array[array.Length], uma posição depois do último elemento. Os índices válidos vão de 0 a Length - 1, então a condição deve ser i < array.Length (ou i < list.Count para uma List, que lança ArgumentOutOfRangeException no lugar).