Search buenodc

Nesta página
  1. 1. A instrução for
  2. 2. Laços aninhados
  3. 3. Escolhendo o laço certo

For, laços aninhados e revisão de repetição

Você já conhece dois laços de repetição: o while, que testa a condição antes de cada repetição, e o do-while, que garante pelo menos uma execução. Mas repare numa situação bem comum: muitas vezes você já sabe, antes mesmo de escrever o laço, exatamente quantas vezes ele precisa repetir, como processar as notas de uma turma com número fixo de alunos. Para esse cenário, C++ tem um terceiro laço, pensado especificamente para ele: o for. Esta semana também mostra que laços podem ser combinados, um dentro do outro, e fecha com um critério prático para escolher, sem dúvida, qual dos três laços usar em cada problema novo.

Base bibliográfica: este material segue a seção 2.3 (Loops) de SAVITCH, C++ Absoluto (Pearson Addison Wesley, 2004), no trecho sobre o comando for e loops aninhados.

1. A instrução for

Nos laços while e do-while, você escreve a inicialização da variável, a condição de parada e a atualização em três linhas separadas do programa. Quando o número de repetições já é conhecido de antemão, o for reúne essas três partes numa única linha, no início do laço:

for (inicializacao; condicao; atualizacao) {
    comandos;
}

A condição é testada antes de cada repetição, igual no while: o bloco também pode executar zero vezes, se ela já começar falsa. Um exemplo direto, somando os números de 1 a 10:

int soma = 0;
for (int n = 1; n <= 10; n++)
    soma = soma + n;

n é declarada e inicializada em 1 dentro do próprio for, a condição testa n <= 10, e n++ roda ao final de cada repetição, sem você precisar escrever esse incremento dentro do bloco.

Equivalência com o while

O for não é uma ferramenta nova de verdade: é uma forma mais compacta de escrever um padrão que você já conhece do while, com a inicialização antes do laço e a atualização como último passo do bloco:

inicializacao;
while (condicao) {
    comandos;
    atualizacao;
}

Exemplo adaptado de Savitch, seção 2.3.

As três partes do for aceitam qualquer expressão, incluindo decremento, o que permite contar para trás:

for (int senha = 10; senha >= 1; senha--)
    cout << senha << endl;

Escopo da variável no for

Quando você declara a variável dentro do próprio for, como o n do primeiro exemplo, ela só existe dentro do laço:

for (int i = 1; i <= 5; i++)
    cout << i << endl;
// i não existe mais aqui

Isso evita que você reaproveite sem querer o mesmo nome de variável mais adiante no programa, para outra finalidade completamente diferente.

Armadilha: ponto e vírgula por engano

for (int contador = 1; contador <= 10; contador++);
    cout << "Ola" << endl;

O ponto e vírgula logo depois do parêntese fecha o for com um comando vazio como corpo. O laço roda dez vezes sem fazer nada, e o cout, que parece estar dentro por causa da indentação, na verdade executa só uma vez, depois que o laço termina. Um erro desses não trava a compilação, e o código continua com essa aparência enganosa: só rodando o programa de verdade é que ele aparece.

🎥 Vídeo 1 de 3: A instrução for (~7 min)

2. Laços aninhados

É perfeitamente possível colocar um laço dentro do corpo de outro laço. O laço de fora, chamado laço externo, controla quantas vezes o laço de dentro, o laço interno, roda por inteiro, do começo ao fim, antes de avançar para a próxima repetição externa.

for (int linha = 1; linha <= 3; linha++) {
    for (int coluna = 1; coluna <= 3; coluna++) {
        cout << linha * coluna << " ";
    }
    cout << endl;
}

O laço externo controla a linha; para cada linha, o laço interno roda inteiro, de coluna 1 até 3, antes do laço externo avançar. O resultado é uma tabuada em formato de grade.

Limite do laço interno

O limite do laço interno não precisa ser um número fixo: pode depender do valor atual da variável do laço externo.

for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= i; j++) {
        cout << "*";
    }
    cout << endl;
}

Aqui, o laço interno repete i vezes: para i igual a 1, mostra um asterisco; para i igual a 2, dois; para i igual a 3, três. O resultado é um triângulo crescendo linha a linha, porque o próprio limite do laço de dentro muda, junto com o laço de fora.

Break e continue no laço interno

Um break ou continue dentro de laços aninhados se aplica sempre ao laço mais interno que o contém, nunca ao laço de fora.

for (int linha = 1; linha <= 3; linha++) {
    for (int coluna = 1; coluna <= 3; coluna++) {
        if (coluna == 2) break;
        cout << linha << "," << coluna << " ";
    }
}

Esse break interrompe só o laço de coluna, o laço interno: ele não afeta o laço de linha, o externo, que continua rodando normalmente. Já o continue não interrompe o laço: ele só pula para a próxima repetição do laço mais interno, deixando o restante das repetições seguir normalmente.

Dois níveis de aninhamento já cobrem a grande maioria dos problemas reais. Quando um programa parece precisar de três ou mais laços aninhados, geralmente vale a pena repensar a lógica antes de continuar empilhando laços: código com muitos níveis de aninhamento fica difícil de ler e mais fácil de esconder um erro.

🎥 Vídeo 2 de 3: Laços aninhados (~6 min)

3. Escolhendo o laço certo

while, do-while e for repetem exatamente a mesma coisa: um bloco de comandos, várias vezes. A diferença entre eles está em quando a condição é testada, e no que você já sabe sobre o problema antes mesmo de escrever a primeira linha do laço. Três perguntas ajudam a escolher:

  • Eu já sei, antes de começar, quantas vezes esse laço precisa repetir? Se sim, como percorrer as notas de uma turma de tamanho fixo, o for é a escolha natural.
  • O bloco precisa rodar pelo menos uma vez, nem que seja só para pedir o primeiro dado ao usuário? Se sim, como confirmar uma senha, o do-while resolve isso diretamente.
  • O número de repetições não é conhecido de antemão, e pode até ser zero? Se sim, como somar números digitados até aparecer um valor de parada, o while é a escolha certa.

Um sinal de alerta

for (int i = 0; i < 1000; i++) {
    cin >> numero;
    if (numero == -1) break;
    soma = soma + numero;
}

Um for com um limite grande e arbitrário, como 1000, dependendo de um break lá dentro para realmente parar, é sinal de que o total não era conhecido de verdade: esse problema pedia um while desde o início, não um for com um limite inventado.

Aplicando a cenários

  • Média de uma turma de 30 alunos: total conhecido → for.
  • Pedir uma senha até o usuário acertar: precisa perguntar ao menos uma vez → do-while.
  • Somar vendas de um caixa até digitar zero para fechar: total desconhecido, pode ser zero → while.
LaçoTesta a condiçãoRepete zero vezes?Quando usar
whileAntesSimRepetições desconhecidas, pode ser zero
do-whileDepoisNão, no mínimo umaPrecisa rodar ao menos uma vez
forAntesSimRepetições conhecidas de antemão

🎥 Vídeo 3 de 3: Quando usar while, do-while ou for (~6 min)

Leitura da Semana 5 - Base: Savitch, C++ Absoluto, seção 2.3. Faça a lista de exercícios e traga suas dúvidas para o encontro síncrono.