O laço for é uma das estruturas de repetição mais utilizadas na linguagem C, especialmente quando o número de iterações é conhecido ou pode ser facilmente determinado. Ele permite executar um bloco de código várias vezes, controlando a variável de controle de forma compacta e legível. Nesta aula, vamos explorar detalhadamente a sintaxe do for, seus componentes, variações com break e continue, e como criar loops aninhados para resolver problemas mais complexos.

Dominar o laço for é essencial para qualquer programador em C, pois ele aparece em algoritmos de ordenação, busca, manipulação de matrizes, processamento de dados e muito mais. Vamos começar pela estrutura básica e depois avançar para técnicas mais avançadas, com exemplos práticos que você pode testar em seu compilador.

Estrutura

A sintaxe do laço for em C é composta por três partes principais entre parênteses, separadas por ponto e vírgula: inicialização, condição e incremento. A estrutura é a seguinte:

for (inicialização; condição; incremento) {
    // bloco de código a ser repetido
}

O fluxo de execução ocorre assim: primeiro, a inicialização é executada (uma única vez). Em seguida, a condição é avaliada; se for verdadeira, o bloco de código é executado. Depois da execução do bloco, o incremento é executado e a condição é avaliada novamente. Esse ciclo continua até que a condição se torne falsa, momento em que o laço termina e o programa prossegue com a próxima instrução após o laço.

É importante notar que qualquer uma das três partes pode ser omitida, mas os ponto e vírgula devem permanecer. Por exemplo, um laço infinito pode ser criado com for (;;), mas isso raramente é usado sem uma forma de saída (como break). O bloco de código pode conter uma única instrução (sem chaves) ou múltiplas instruções entre chaves.

// Exemplo: imprimir números de 0 a 4
#include <stdio.h>

int main() {
    for (int i = 0; i < 5; i++) {
        printf("%d\n", i);
    }
    return 0;
}

Neste exemplo, a variável i é inicializada com 0, a condição é i < 5 e o incremento é i++. O resultado será a impressão dos números 0, 1, 2, 3 e 4, cada um em uma linha.

Inicialização, condição, incremento

Cada parte do laço for tem um papel específico e pode ser personalizada de acordo com a necessidade do algoritmo. Vamos analisar cada uma delas em detalhes.

Inicialização

A inicialização é executada apenas uma vez, antes de o laço começar. Normalmente, ela define a variável de controle com um valor inicial. Em C moderno (padrão C99 em diante), é possível declarar a variável diretamente dentro da inicialização, como vimos no exemplo anterior (int i = 0). Essa variável tem escopo local ao laço, ou seja, não pode ser acessada fora dele.

// Inicialização com declaração da variável
for (int i = 10; i > 0; i--) {
    printf("%d ", i);
}
// i não está acessível aqui

Se você precisar usar a variável após o laço, declare-a antes do for:

int i;
for (i = 0; i < 10; i++) {
    // ...
}
printf("Valor final de i: %d\n", i); // 10

Também é possível inicializar múltiplas variáveis separando-as por vírgula, como for (i = 0, j = 10; ...), mas isso pode prejudicar a legibilidade.

Condição

A condição é uma expressão relacional ou lógica que é avaliada antes de cada iteração. Se a condição for verdadeira (diferente de zero), o bloco é executado; se for falsa (zero), o laço é encerrado. A condição é testada no início de cada iteração, inclusive na primeira. Portanto, se a condição já for falsa no início, o bloco nunca será executado.

// Condição que nunca é verdadeira
for (int i = 5; i < 0; i++) {
    printf("Nunca imprimirá\n");
}

A condição pode ser qualquer expressão válida em C, incluindo chamadas de função, mas é comum usar comparações simples. Cuidado com erros de digitação como usar = em vez de ==, pois isso pode causar um loop infinito ou comportamento inesperado.

Incremento

O incremento é executado ao final de cada iteração, após o bloco de código. Ele atualiza a variável de controle, geralmente incrementando ou decrementando. Pode ser qualquer expressão, não apenas i++. Por exemplo, você pode usar i += 2 para avançar de dois em dois, ou i *= 2 para dobrar o valor a cada iteração.

// Imprimir números pares de 0 a 10
for (int i = 0; i <= 10; i += 2) {
    printf("%d ", i);
}
// Saída: 0 2 4 6 8 10

É importante que o incremento eventualmente torne a condição falsa; caso contrário, teremos um loop infinito. Por exemplo, se você esquecer o incremento, a condição permanece verdadeira para sempre.

break e continue

Dentro do laço for, você pode usar as instruções break e continue para controlar o fluxo de execução de maneira mais refinada.

break

A instrução break encerra imediatamente o laço mais interno em que está contida, transferindo o controle para a próxima instrução após o laço. Isso é útil quando você deseja interromper a repetição antes que a condição se torne falsa, por exemplo, ao encontrar um valor específico.

// Procurar o número 7 em um intervalo
for (int i = 0; i < 10; i++) {
    if (i == 7) {
        printf("Encontrado: %d\n", i);
        break; // sai do laço
    }
}
// Após o break, o controle vem para cá

No exemplo acima, quando i chega a 7, o laço é interrompido, e as iterações seguintes (8 e 9) não são executadas. O break é especialmente útil em loops infinitos ou quando a condição de saída depende de cálculos complexos.

continue

A instrução continue pula o restante do bloco de código da iteração atual e vai diretamente para o incremento, iniciando a próxima iteração (se a condição ainda for verdadeira). Ela não encerra o laço, apenas ignora as instruções restantes da iteração corrente.

// Imprimir apenas números ímpares de 0 a 9
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) {
        continue; // pula para o incremento
    }
    printf("%d ", i);
}
// Saída: 1 3 5 7 9

No exemplo, quando i é par, a instrução continue faz com que o printf seja ignorado, e o laço prossegue com a próxima iteração. O continue é útil para filtrar valores sem precisar de uma estrutura if-else complexa.

É importante lembrar que break e continue afetam apenas o laço mais interno. Em loops aninhados, eles atuam no nível em que estão escritos.

Loops aninhados

Loops aninhados são laços for dentro de outros laços. Eles são comuns quando é necessário percorrer estruturas bidimensionais, como matrizes, ou quando precisamos combinar iterações de múltiplas variáveis. O laço externo controla as iterações principais, e o laço interno é executado completamente para cada iteração do externo.

// Exemplo: imprimir uma tabuada de multiplicação (1 a 5)
#include <stdio.h>

int main() {
    for (int i = 1; i <= 5; i++) {
        for (int j = 1; j <= 5; j++) {
            printf("%d x %d = %d\t", i, j, i * j);
        }
        printf("\n"); // nova linha após cada linha da tabela
    }
    return 0;
}

Esse código gera uma tabela 5x5 com as multiplicações. O laço externo (i) representa a primeira linha e varia de 1 a 5; para cada valor de i, o laço interno (j) percorre todos os valores de 1 a 5, imprimindo o produto, e depois o laço externo imprime uma nova linha.

Loops aninhados podem ter qualquer profundidade, mas é importante manter o código legível. Um exemplo clássico é o preenchimento de uma matriz:

// Preencher uma matriz 3x3 com valores sequenciais
int matriz[3][3];
int contador = 1;
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        matriz[i][j] = contador++;
    }
}

Quando usar loops aninhados, preste atenção à complexidade: se o laço externo tem n iterações e o interno m, o total de execuções do bloco interno será n * m. Isso pode se tornar ineficiente para grandes valores, então avalie se há alternativas.

Uma aplicação comum de loops aninhados é a impressão de padrões, como triângulos de asteriscos:

// Imprimir um triângulo retângulo de altura 5
for (int i = 1; i <= 5; i++) {
    for (int j = 1; j <= i; j++) {
        printf("*");
    }
    printf("\n");
}

Nesse caso, o laço interno depende do valor do externo, criando um padrão crescente.

Boas práticas e observações finais

Ao utilizar o laço for, siga estas recomendações para escrever código mais claro e evitar erros comuns:

  • Declare a variável de controle dentro do próprio for (C99 ou superior) para limitar seu escopo e evitar conflitos de nomes.
  • Use nomes significativos para a variável de controle, como i, j para índices, mas evite nomes muito vagos em loops complexos.
  • Evite modificar a variável de controle dentro do corpo do laço, a menos que seja intencional; isso pode dificultar a compreensão.
  • Prefira o for quando o número de iterações for conhecido; para loops baseados em condições, o while pode ser mais adequado.
  • Cuidado com loops infinitos: sempre verifique se a condição pode se tornar falsa.
  • Em loops aninhados, mantenha a indentação consistente para melhorar a legibilidade.
  • Teste os limites do laço (primeira e última iteração) para garantir que a condição está correta.

O laço for é uma ferramenta poderosa e versátil. Com a prática, você aprenderá a usá-lo de forma eficiente em diversas situações.

Referências

Exercícios

  1. Escreva um programa em C que use um laço for para imprimir todos os números inteiros de 1 a 20, mas que pule os múltiplos de 3. Utilize continue para essa tarefa.

    ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        for (int i = 1; i <= 20; i++) {
            if (i % 3 == 0) {
                continue;
            }
            printf("%d ", i);
        }
        printf("\n");
        return 0;
    }
  2. Crie um código que use um laço for para calcular a soma dos números pares entre 1 e 100 (inclusive). Imprima o resultado.

    ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        int soma = 0;
        for (int i = 2; i <= 100; i += 2) {
            soma += i;
        }
        printf("Soma dos pares de 1 a 100: %d\n", soma);
        return 0;
    }
  3. Escreva um programa que utilize um laço for aninhado para imprimir um triângulo de números, onde cada linha contém números de 1 até o número da linha. Exemplo para altura 5:

    1
    12
    123
    1234
    12345

    ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        int altura = 5;
        for (int i = 1; i <= altura; i++) {
            for (int j = 1; j <= i; j++) {
                printf("%d", j);
            }
            printf("\n");
        }
        return 0;
    }
  4. Utilizando break, escreva um programa que percorra os números de 1 a 100 e pare ao encontrar o primeiro número que seja divisível por 7 e por 9 simultaneamente. Imprima esse número.

    ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        for (int i = 1; i <= 100; i++) {
            if (i % 7 == 0 && i % 9 == 0) {
                printf("Encontrado: %d\n", i);
                break;
            }
        }
        return 0;
    }
  5. Escreva um programa que use um laço for para gerar os primeiros 10 termos da sequência de Fibonacci (0, 1, 1, 2, 3, 5, 8, 13, 21, 34). Dica: mantenha duas variáveis para os dois últimos termos.

    ✓ Resposta:
    #include <stdio.h>
    
    int main() {
        int a = 0, b = 1;
        printf("%d %d ", a, b);
        for (int i = 2; i < 10; i++) {
            int proximo = a + b;
            printf("%d ", proximo);
            a = b;
            b = proximo;
        }
        printf("\n");
        return 0;
    }