C++ Laços Aninhados

O corpo de um laço pode ter qualquer coisa: um if, um std::cin… e também outro laço. Um laço dentro de outro se chama laço aninhado (como um ninho, uma coisa dentro da outra). É assim que se percorre qualquer coisa que tenha linhas e colunas: uma tabela, um tabuleiro, uma planilha de notas, um desenho na tela.

Você vai aprender
  • Como o laço de dentro roda inteiro a cada volta do laço de fora.
  • Como gerar todas as combinações de duas listas.
  • Como montar a tabuada completa, do 1 ao 10, em forma de tabela.
  • Como desenhar um retângulo e um triângulo de *.
  • Como calcular quantas vezes o corpo de dentro roda (n × m).
  • Os erros típicos: a quebra de linha no lugar errado, o contador que não é zerado e a mesma variável nos dois laços.

Os programas foram compilados com o g++ 15 na máquina fictícia da Ana, na pasta ~/cpp, com g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa. Antes desta aula, é bom conhecer o for e o for de intervalo.


A ideia: o relógio

Olhe para um relógio digital. O ponteiro das horas anda devagar; o dos minutos anda rápido. Para cada hora, os minutos dão uma volta completa, de 00 a 59. Só depois disso a hora avança uma vez, e os minutos recomeçam do 00.

  • O laço de fora é o das horas: anda devagar.
  • O laço de dentro é o dos minutos: dá todas as voltas dele a cada passo do de fora, e recomeça do zero na próxima.

Em 24 horas, os minutos mudam 24 × 60 = 1440 vezes. Guarde essa multiplicação: ela volta na seção 5.


1. O primeiro laço aninhado

A Ana dá aula para 3 turmas, e cada turma fará 2 provas. O programa lista as provas de cada turma:

#include <iostream>

int main() {
    for (int turma = 1; turma <= 3; turma++) {
        std::cout << "Turma " << turma << ":";
        for (int prova = 1; prova <= 2; prova++) {
            std::cout << " prova " << prova;
        }
        std::cout << '\n';
    }
}
for (int turma …)
O laço de fora: uma volta por turma (3 voltas).
std::cout << "Turma "
Roda uma vez por turma, antes do laço de dentro: começa a linha.
for (int prova …)
O laço de dentro: está no corpo do de fora, então roda inteiro (2 voltas) em cada turma.
std::cout << '\n';
Roda uma vez por turma, depois do laço de dentro: termina a linha.
$ g++ -std=c++23 -Wall -Wextra turmas.cpp -o turmas
$ ./turmas
Turma 1: prova 1 prova 2
Turma 2: prova 1 prova 2
Turma 3: prova 1 prova 2

Passo a passo

OrdemturmaprovaO que aconteceu
11—Mostra Turma 1:
211Mostra prova 1
312Mostra prova 2; o laço de dentro termina (prova vira 3)
41—Pula a linha; o de fora avança: turma vira 2
521O laço de dentro recomeça: int prova = 1 de novo
…………

O ponto central: a cada volta do laço de fora, o for de dentro começa do zero, com o seu início (int prova = 1) rodando de novo. É como os minutos do relógio voltando ao 00.

Todas as combinações

Laços aninhados geram todas as combinações de duas listas. A Ana tem 2 camisetas e 3 calças. Quantas roupas diferentes ela consegue montar?

#include <iostream>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> camisetas = {"branca", "preta"};
    std::vector<std::string> calcas = {"jeans", "bege", "cinza"};
    for (const auto& camiseta : camisetas) {
        for (const auto& calca : calcas) {
            std::cout << "camiseta " << camiseta << " + calça " << calca << '\n';
        }
    }
}
$ g++ -std=c++23 -Wall -Wextra roupas.cpp -o roupas
$ ./roupas
camiseta branca + calça jeans
camiseta branca + calça bege
camiseta branca + calça cinza
camiseta preta + calça jeans
camiseta preta + calça bege
camiseta preta + calça cinza

2 camisetas × 3 calças = 6 roupas. A camiseta (laço de fora) muda devagar; a calça (laço de dentro) passa por todas as opções antes da camiseta mudar. Os dois laços são for de intervalo: qualquer tipo de laço pode ser aninhado com qualquer outro.


2. A tabuada completa

Na aula for, um laço fazia a tabuada de um número. Para todas, do 1 ao 10, basta colocar aquele laço dentro de outro que escolhe o número. Para a saída virar uma tabela alinhada, cada número ocupa 4 posições com std::setw(4) ("set width", definir a largura, da aula iomanip):

#include <iomanip>
#include <iostream>

int main() {
    for (int linha = 1; linha <= 10; linha++) {
        for (int coluna = 1; coluna <= 10; coluna++) {
            std::cout << std::setw(4) << linha * coluna;
        }
        std::cout << '\n';
    }
}
$ g++ -std=c++23 -Wall -Wextra tabuada.cpp -o tabuada
$ ./tabuada
   1   2   3   4   5   6   7   8   9  10
   2   4   6   8  10  12  14  16  18  20
   3   6   9  12  15  18  21  24  27  30
   4   8  12  16  20  24  28  32  36  40
   5  10  15  20  25  30  35  40  45  50
   6  12  18  24  30  36  42  48  54  60
   7  14  21  28  35  42  49  56  63  70
   8  16  24  32  40  48  56  64  72  80
   9  18  27  36  45  54  63  72  81  90
  10  20  30  40  50  60  70  80  90 100

Os nomes linha e coluna dizem o papel de cada contador. Essa é a regra de ouro das tabelas:

  • o laço de fora escolhe a linha;
  • o laço de dentro anda pelas colunas daquela linha, mostrando um valor por vez, sem pular linha;
  • o '\n' fica entre o fim do laço de dentro e o fim do de fora: um por linha.

Cada número da tabela é linha * coluna: na linha 7, coluna 8, aparece 56.


3. Desenhar com *: retângulo

Desenhar figuras com caracteres é o melhor treino de laços aninhados, porque você vê cada volta. Um retângulo de 3 linhas por 5 colunas:

#include <iostream>

int main() {
    for (int linha = 1; linha <= 3; linha++) {
        for (int coluna = 1; coluna <= 5; coluna++) {
            std::cout << '*';
        }
        std::cout << '\n';
    }
}
$ g++ -std=c++23 -Wall -Wextra retangulo.cpp -o retangulo
$ ./retangulo
*****
*****
*****

O laço de dentro desenha uma linha de 5 estrelas. O de fora repete isso 3 vezes, pulando de linha entre uma e outra. Troque o 3 e o 5 e o retângulo muda de tamanho.


4. Desenhar com *: triângulo

No retângulo, toda linha tem o mesmo número de estrelas. No triângulo, a linha 1 tem 1 estrela, a linha 2 tem 2, a linha 3 tem 3… Ou seja: a linha n tem n estrelas. O truque é fazer o laço de dentro depender do contador do de fora:

#include <iostream>

int main() {
    int altura = 5;
    for (int linha = 1; linha <= altura; linha++) {
        for (int estrela = 1; estrela <= linha; estrela++) {
            std::cout << '*';
        }
        std::cout << '\n';
    }
}
int altura = 5;
Quantas linhas o triângulo terá.
for (int linha = 1; linha <= altura; linha++)
Laço de fora: uma volta por linha, de 1 a 5.
estrela <= linha
O pulo do gato: o limite do laço de dentro não é fixo, é o número da linha atual. Na linha 1, ele dá 1 volta; na linha 4, dá 4.
std::cout << '\n';
Depois das estrelas de cada linha, pula a linha.
$ g++ -std=c++23 -Wall -Wextra triangulo.cpp -o triangulo
$ ./triangulo
*
**
***
****
*****

Com essa ideia (o laço de dentro olhando para o contador do de fora), dá para desenhar triângulos de cabeça para baixo (estrela <= altura - linha + 1), pirâmides (espaços antes das estrelas), escadas… Os exercícios do fim da aula trazem algumas.

Missão: em vez de estrelas, desenhe o triângulo com números: em cada linha, mostre a variável do laço de dentro. Com altura 4, as linhas devem ser 1, 12, 123 e 1234.

#include <iostream>

int main() {
    int altura = 4;
    for (int linha = 1; linha <= altura; linha++) {
        for (int estrela = 1; estrela <= linha; estrela++) {
            std::cout << '*';
        }
        std::cout << '\n';
    }
}
#include <iostream>

int main() {
    int altura = 4;
    for (int linha = 1; linha <= altura; linha++) {
        for (int numero = 1; numero <= linha; numero++) {
            std::cout << numero;
        }
        std::cout << '\n';
    }
}

5. Quantas vezes o corpo de dentro roda?

Se o laço de fora dá n voltas e o de dentro dá m voltas em cada uma, o corpo de dentro roda n × m vezes. Um contador confirma:

#include <iostream>

int main() {
    int voltas = 0;
    for (int i = 1; i <= 3; i++) {
        for (int j = 1; j <= 4; j++) {
            voltas++;
        }
    }
    std::cout << "3 x 4: o corpo de dentro rodou " << voltas << " vezes\n";

    voltas = 0;
    for (int i = 1; i <= 1000; i++) {
        for (int j = 1; j <= 1000; j++) {
            voltas++;
        }
    }
    std::cout << "1000 x 1000: " << voltas << " vezes\n";

    voltas = 0;
    for (int linha = 1; linha <= 5; linha++) {
        for (int estrela = 1; estrela <= linha; estrela++) {
            voltas++;
        }
    }
    std::cout << "Triângulo de altura 5: " << voltas << " estrelas\n";
}
$ g++ -std=c++23 -Wall -Wextra contar.cpp -o contar
$ ./contar
3 x 4: o corpo de dentro rodou 12 vezes
1000 x 1000: 1000000 vezes
Triângulo de altura 5: 15 estrelas
  • 3 × 4 = 12: a conta simples.
  • 1000 × 1000 = 1 milhão: dois laços de mil voltas parecem pouco, mas juntos dão um milhão. Com três laços de mil, seria um bilhão. É por isso que laços aninhados são o primeiro lugar a olhar quando um programa fica lento.
  • Triângulo: 1 + 2 + 3 + 4 + 5 = 15: quando o laço de dentro depende do de fora, não é n × m; some as voltas de cada linha. (Para altura n, dá n × (n + 1) / 2, cerca de metade do quadrado n × n.)
Contas para conferir

Antes de rodar, estime quantas linhas a saída terá. Se o seu triângulo de altura 5 mostrou 25 estrelas, o laço de dentro está usando um limite fixo (<= altura) em vez de <= linha.


Formas diferentes de escrever

  • Qualquer laço dentro de qualquer laço: for dentro de for é o mais comum, mas vale while dentro de for, for de intervalo dentro de while… Com while, lembre-se de zerar o contador de dentro a cada volta do de fora (veja Quando dá errado).
  • Três ou mais níveis: funcionam do mesmo jeito (um cubo, dias × horas × minutos), mas ficam difíceis de ler. Acima de dois níveis, considere mover o laço de dentro para uma função com nome próprio, como desenhar_linha(n).
  • Nomes de contadores: i e j são a tradição (e k para um terceiro nível). Nomes como linha e coluna deixam o código autoexplicativo; use-os sempre que o sentido for claro.
  • Sair dos dois laços de uma vez: o break sai só do laço de dentro. Para sair dos dois, veja break e continue.

Os laços aninhados aparecem de novo em Arrays Multidimensionais, onde servem para percorrer tabelas guardadas na memória, como um tabuleiro de jogo da velha.


Quando dá errado

Tudo saiu numa linha só (o '\n' ficou fora do laço de fora)
#include <iostream>

int main() {
    for (int linha = 1; linha <= 3; linha++) {
        for (int coluna = 1; coluna <= 5; coluna++) {
            std::cout << '*';
        }
    }
    std::cout << '\n';
}
$ g++ -std=c++23 -Wall -Wextra semquebra.cpp -o semquebra
$ ./semquebra
***************

O que aconteceu: as 15 estrelas foram desenhadas, mas o '\n' está depois da } do laço de fora: roda uma vez só, no fim. Se ele estivesse dentro do laço de dentro, o contrário aconteceria: uma estrela por linha, 15 linhas.

Como consertar: o '\n' vai dentro do laço de fora e depois do de dentro, entre as duas }. Indentar direito ajuda a ver onde cada linha está.

Só a primeira linha foi desenhada (o contador de dentro não foi zerado)
#include <iostream>

int main() {
    int linha = 1;
    int coluna = 1;
    while (linha <= 3) {
        while (coluna <= 5) {
            std::cout << '*';
            coluna++;
        }
        std::cout << '\n';
        linha++;
    }
}
$ g++ -std=c++23 -Wall -Wextra semzerar.cpp -o semzerar
$ ./semzerar
*****
                 « linha 2: vazia
                 « linha 3: vazia

O que aconteceu: com while, o contador coluna foi criado uma vez só, lá em cima. Depois da primeira linha, ele vale 6 e nunca volta a 1: nas linhas 2 e 3, a condição coluna <= 5 já começa falsa e o laço de dentro não roda. Só os '\n' aparecem.

Como consertar: crie (ou zere) o contador de dentro dentro do laço de fora: int coluna = 1; logo depois de while (linha <= 3) {. Melhor ainda: use for, que faz isso sozinho com o seu início.

A mesma variável nos dois laços
#include <iostream>

int main() {
    for (int i = 1; i <= 2; i++) {
        for (int i = 1; i <= 3; i++) {
            std::cout << "i = " << i << '\n';
        }
        std::cout << "fim da linha " << i << '\n';
    }
}
$ g++ -std=c++23 -Wall -Wextra mesmoi.cpp -o mesmoi
$ ./mesmoi
i = 1
i = 2
i = 3
fim da linha 1
i = 1
i = 2
i = 3
fim da linha 2

O que aconteceu: compila e roda, mas há duas variáveis chamadas i. Dentro do laço de dentro, o i de dentro esconde o de fora: não há como saber "em que linha estou" ali. Se você quisesse mostrar a linha e a coluna, não conseguiria. Nem o -Wall -Wextra avisa; só a opção -Wshadow ("sombra"):

$ g++ -std=c++23 -Wall -Wextra -Wshadow mesmoi.cpp -o mesmoi
mesmoi.cpp: In function ‘int main()’:
mesmoi.cpp:5:18: warning: declaration of ‘i’ shadows a previous local [-Wshadow]
    5 |         for (int i = 1; i <= 3; i++) {
      |                  ^
mesmoi.cpp:4:14: note: shadowed declaration is here
    4 |     for (int i = 1; i <= 2; i++) {
      |              ^

Como consertar: um nome diferente para cada nível (i e j, ou linha e coluna).

O triângulo virou um quadrado

O que aconteceu: o limite do laço de dentro é fixo (estrela <= altura), então toda linha tem o mesmo número de estrelas.

Como consertar: faça o limite depender do contador de fora: estrela <= linha.


Referência

PadrãoForma
Tabela (linhas × colunas)for (linha…) { for (coluna…) { mostra; } '\n'; }
Todas as combinaçõesfor (a : lista1) { for (b : lista2) { … } }
Triângulofor (int l = 1; l <= n; l++) { for (int e = 1; e <= l; e++) … }
Voltas do corpo de dentron × m (limites fixos); soma das voltas de cada linha (limite variável)
Sair dos doisVariável de controle ou função com return (break e continue)

Exercícios

1. Quantas vezes?

Quantas estrelas for (int i = 0; i < 4; i++) { for (int j = 0; j < 6; j++) { std::cout << '*'; } } mostra?

2. O limite do triângulo

Complete o laço de dentro para desenhar um triângulo (linha 1 com 1 estrela, linha 2 com 2…):

for (int l = 1; l <= 5; l++) { for (int e = 1; e <= ; e++) std::cout << '*'; std::cout << '\n'; }

3. Triângulo de altura 4

Quantas estrelas tem, no total, um triângulo de altura 4 (1 + 2 + 3 + 4)?

4. Num laço aninhado, o laço de dentro…

5. Para desenhar uma tabela, onde fica o std::cout << '\n';?

6. Dois laços aninhados de 10 mil voltas cada: quantas vezes o corpo de dentro roda?

Missão final: o triângulo e a conta das estrelas

Missão: desenhe um triângulo de * com altura 5 e, enquanto desenha, conte as estrelas numa variável total. No fim, mostre Total: 15 estrelas.

#include <iostream>

int main() {
    int altura = 5;
    int total = 0;
    // desenhe o triângulo aqui

    std::cout << "Total: " << total << " estrelas\n";
}
#include <iostream>

int main() {
    int altura = 5;
    int total = 0;
    for (int linha = 1; linha <= altura; linha++) {
        for (int estrela = 1; estrela <= linha; estrela++) {
            std::cout << '*';
            total++;
        }
        std::cout << '\n';
    }
    std::cout << "Total: " << total << " estrelas\n";
}

Resumo

  • Um laço aninhado é um laço dentro do corpo de outro. A cada volta do de fora, o de dentro roda inteiro, começando do zero.
  • Em tabelas: o de fora escolhe a linha, o de dentro anda pelas colunas, e o '\n' fica entre o fim do de dentro e o fim do de fora.
  • Se o limite do de dentro depende do contador do de fora (e <= linha), as linhas têm tamanhos diferentes: é o triângulo.
  • Voltas do corpo de dentro: n × m com limites fixos. Dois laços de 1000 já dão 1 milhão.
  • Use um nome diferente em cada nível, e, com while, zere o contador de dentro a cada volta do de fora.