Por que um laço for
Um switch escolhe um ramo para executar uma única vez. Mas programas reais precisam fazer algo repetidamente: imprimir cada pontuação, somar uma lista de números, desenhar 10 linhas de uma grade. O laço for é o burro de carga do C++ para repetir código um número conhecido de vezes, com um contador embutido que você controla.
Tudo de que um laço for precisa vive em um cabeçalho compacto, então toda a história de "quantas vezes e como" fica visível num relance.
O cabeçalho de três partes
O cabeçalho de um laço for tem três partes separadas por ponto e vírgula: um inicializador, uma condição e uma atualização.
for (initializer; condition; update) {
// corpo: executa enquanto a condição for verdadeira
}
Eles executam em uma ordem específica: o inicializador executa uma vez no início; depois a condição é verificada antes de cada iteração; o corpo executa só se a condição for true; e a atualização executa no fim de cada iteração, logo antes de a condição ser verificada de novo.
Aqui int i = 0 executa uma vez. Depois i < 5 é verificado: enquanto vale, o corpo imprime e i++ incrementa o contador. Quando i chega a 5 a condição é false, então o laço sai e done é impresso. O corpo executa exatamente 5 vezes, com i assumindo os valores 0 a 4.
Declarar o contador dentro do cabeçalho (int i = 0) mantém i com escopo limitado ao laço: ele não existe depois da chave de fechamento, que é exatamente o que você quer.
Contar para cima, para baixo e em passos
A parte de atualização não se limita a i++. Você pode contar para baixo, avançar em qualquer quantidade ou percorrer o índice de um array.
O primeiro laço executa enquanto i > 0, decrementando a cada vez, então imprime 5 4 3 2 1. O segundo soma 2 a cada passagem e usa <= 10 porque 10 é um valor que queremos incluir. Combine sua condição com sua atualização: contar para baixo combina com > ou >=, contar para cima com < ou <=.
Percorrer um array
O uso mais comum de um laço de contagem é percorrer um array por índice. O contador funciona também como a posição que você lê.
Note que a condição é i < n, não i <= n. Um array de 5 elementos tem índices válidos de 0 a 4; o índice 5 está além do fim. Ler scores[5] é comportamento indefinido: pode imprimir lixo, travar, ou parecer funcionar e corromper a memória silenciosamente. O padrão i < n é o padrão seguro para qualquer array baseado em zero.
Se você só precisa dos valores e não do índice, um for baseado em intervalo é mais limpo. Recorra ao laço indexado clássico quando realmente precisar da posição.
break e continue
Duas palavras-chave permitem mudar o fluxo no meio do laço. break sai do laço imediatamente; continue pula o resto da iteração atual e salta para a atualização.
O primeiro laço para no momento em que encontra 7 e nunca verifica o resto. O segundo usa continue para pular a impressão do corpo sempre que i for par: a atualização i++ ainda executa, então o laço continua avançando. Uma armadilha sutil: continue salta para a atualização, então se você algum dia depender de continue dentro de um laço cujo contador é atualizado dentro do corpo em vez do cabeçalho, você pode pular essa atualização por acidente e girar para sempre.
Laços aninhados
Coloque um for dentro de outro para trabalhar com grades, tabelas ou pares. O laço interno executa por completo a cada passo individual do laço externo.
Isso imprime uma grade de multiplicação 3x3. O laço externo fixa uma row, o laço interno varre cada col daquela linha, e então uma quebra de linha encerra a linha. Dê nomes distintos aos contadores (row/col, não i/i): reutilizar um nome oculta o externo e produz bugs desconcertantes. Fique de olho no custo também: aninhar um laço de n dentro de outro de n executa o corpo n * n vezes, o que acumula rápido.
Armadilhas comuns
Algumas armadilhas explicam a maioria dos bugs de laços for em C++:
- Deslocamento por um:
i <= ncom um tamanho baseado em zero lê um elemento além do fim. Usei < n. - Underflow sem sinal: contar para baixo com um tipo sem sinal nunca fica negativo.
for (size_t i = n - 1; i >= 0; i--)repete para sempre, porquei >= 0é sempre verdadeiro para um valor sem sinal: quandoié0,i--dá a volta para um número positivo enorme. Use umintcom sinal para contagens decrescentes, ou reescreva a condição. - Modificar o contador dentro do corpo: mudar
ino corpo além do cabeçalho torna a contagem do laço imprevisível. Escolha um único lugar.
// BUG: infinite loop - unsigned i is never < 0
for (size_t i = n - 1; i >= 0; i--) {
process(arr[i]);
}
Contadores de ponto flutuante são outro perigo silencioso: for (double x = 0.0; x != 1.0; x += 0.1) pode nunca atingir exatamente 1.0 porque 0.1 não pode ser armazenado com precisão. Faça o laço com uma contagem inteira e calcule o valor dentro, ou use < em vez de !=.
Próximo: laços while
O laço for brilha quando você conhece a contagem de antemão. Mas às vezes você precisa repetir até uma condição mudar (ler entrada até o fim do arquivo, tentar de novo até dar certo) sem um número fixo de passos. Esse é o trabalho do laço while, que reduz o cabeçalho a apenas uma condição. É a próxima página.
Perguntas frequentes
Como se escreve um laço for em C++?
Coloque três partes no cabeçalho separadas por ponto e vírgula: um inicializador, uma condição e uma atualização. for (int i = 0; i < 5; i++) { cout << i; } executa o corpo com i assumindo os valores 0, 1, 2, 3, 4. O laço para assim que a condição se torna false.
Qual é a diferença entre um laço for e um laço for baseado em intervalo em C++?
Um for clássico te dá um contador de índice que você controla (for (int i = 0; i < n; i++)), de que você precisa quando quer a posição ou quer avançar de um jeito personalizado. Um for baseado em intervalo (for (int x : v)) esconde o índice e simplesmente entrega cada elemento: mais limpo quando você só precisa dos valores.
Por que meu laço for em C++ executa uma vez a mais ou uma vez a menos?
Esse é o clássico erro de deslocamento por um (off-by-one). Usar <= em vez de < com um tamanho baseado em zero executa uma iteração a mais e lê além do fim do array; usar < quando você queria incluir o último valor o deixa uma vez curto. Para um array de tamanho n, o padrão seguro é for (int i = 0; i < n; i++).