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
fore 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-whileresolve 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ço | Testa a condição | Repete zero vezes? | Quando usar |
|---|---|---|---|
while | Antes | Sim | Repetições desconhecidas, pode ser zero |
do-while | Depois | Não, no mínimo uma | Precisa rodar ao menos uma vez |
for | Antes | Sim | Repetiçõ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.