Aula - Loops

Aula por Rogério Júnior e João Pedro Castro

Na última aula exploramos as estruturas condicionais e aprendemos a direcionar o programa a partir de condições. Agora vamos aprender sobre os Loops, também conhecidos como laços ou estruturas de repetição. Com eles poderemos fazer nossos códigos repetirem determinadas tarefas quantas vezes quisermos, e é (mais uma vez) um dos pilares da programação, aparecendo na imensa maioria dos problemas; seja para receber um valor N vezes, para realizar um cálculo mais complexo, etc.

Operadores de Atribuição

Esta breve sessão é só para introduzir operadores que servem para "economizar" código, ou seja, escrever menos e deixar ele mais fácil de ser lido. Eles são usados por todo programador de nível médio para cima, então é uma ótima ideia os aprender.

Já vimos algumas expressões como x = x + 1, que significa: faça com que a variável x tenha seu valor antigo adicionado em um. Por exemplo, se x = 5, então depois dessa linha o valor de x vira 6. Mas podemos escrever de outro jeito; no caso específico de expressões no formato x = x + y (onde x é uma variável e y é um valor qualquer, podendo ser uma variável também) podemos fazer: x += y. Outros exemplos:

  • x = x - y \rightarrow x -= y
  • x = x * y \rightarrow x *= y
  • x = x / y \rightarrow x /= y
  • x = x % y \rightarrow x %= y

No caso específico de adicionar 1 ou subtrair 1 de uma variável também existem outros tipos de operadores. Para acrescentar existe o x++ e o ++x, assim como para subtrair existe o x-- e o --x. Se essas expressões forem usadas com o objetivo exclusivo de incrementar/decrementar em 1 a variável, tanto faz usar a com o símbolo para direita ou esquerda (pós e pré incremento/decremento, respectivamente). Mas caso esse valor esteja sendo impresso, por exemplo, em cout << x++; a ordem das operações é:

  1. Imprime o valor de x.
  2. Incrementa o valor de x em 1.

Enquanto no cout << ++x; temos a ordem inversa. Então para um x = 7, teríamos sendo impresso o 7 para o x++, enquanto no caso do ++x 8 é impresso, mas depois do cout em ambos os casos x terá seu valor alterado para 8.

While

O while se traduz para enquanto, e diferente do if (se) é possível perceber pelo nome que ele é usado para um código ser repetido várias vezes. A sua estrutura básica é:

A condição segue o exato mesmo modelo da condição do if, e o código é executado enquanto a condição for verdadeira. Cada repetição é chamada de iteração, podendo existir nenhuma, dez, um milhão, ou até infinitas iterações (loops infinitos, que devem ser evitados, afinal o código nunca termina de rodar). O fluxograma  do while é:

Seguem alguns exemplos de uso abaixo.

Imprimir os números de 1 até N

O que esse código está fazendo é inicializando uma variável auxiliar i que começa em 1, e então declara um loop while que testa enquanto i <= n. Para o caso de n = 10 temos a primeira checagem como 1 <= 10 que é verdadeiro, então entramos no código e 1 é impresso, assim como i é incrementado em 1, virando 2 (se o i não tivesse sido incrementado teríamos um loop infinito, que imprimiria infinitos 1).

Agora voltamos para a condição, que se tornou 2 <= 10, que também é verdadeira; e assim segue até i = 10, onde a condição de 10 <= 10 ainda é verdadeira, mas ao incrementar i em 1, temos i = 11, que torna a condição 11 <= 10 falsa, e quebra o loop. Perceba que poderíamos fazer esse mesmo código sem o while, supondo que nas restrições do problema são n <= 100000 podemos fazer:

E o código ainda funcionaria da mesma forma. Obviamente escrever esse if cem mil vezes é impraticável, mas é uma boa maneira de perceber como o while são só muitos (as vezes infinitos) if juntos.

Contagem regressiva

Da mesma forma  que fizemos no exemplo passado podemos realizar a contagem de N até 1, dessa forma:

A lógica é a mesma, mas começamos com o i = 10, e enquanto o i > 0 imprimimos o i e depois o diminuímos em 1. Começando pelo 10, depois indo para o 9, etc, até o 1, e ao chegar no 0 o loop quebra.

Soma até parar

Adivinhe o número secreto

Tabuada - Problema para focar

Resolva esse problema antes de prosseguir. Não recomendo olhar a solução antes de tentar resolver por um bom tempo, sinta-se livre para voltar na aula e reler o conteúdo já passado.

Solução Tabuada

[collapse]

For

O loop for serve para deixar o código mais conciso em alguns casos específicos, como percorrer estruturas de dados (que iremos falar na próxima aula),  e também códigos  onde uma inicialização é necessária (como uma variável auxiliar), juntamente da condição e atualização, tudo em uma única linha. Essa é sua estrutura básica:

Ele acaba sendo o loop principal, pois essas três características são usuais em quase todo loop. Porém, lembre-se que é possível fazer qualquer loop somente com o while, ou somente com o for, a questão é que em alguns casos é mais confortável usar um, ou outro. Esse é o seu fluxograma:

Note que a inicialização ocorre somente uma vez, no começo, enquanto a condição é checada antes de toda iteração, e a atualização ocorre depois de toda iteração. Um aviso muito importante, que já falei na aula anterior, é o de que variáveis declaradas dentro de um loop ou estrutura condicional só existem dentro daquele único loop ou estrutura condicional, e tentar usar elas fora receberá um erro ao compilar de was not declared in this scope. Segue alguns exemplos de uso.

Imprimir os números de 1 até N

Viu como o código fica bem mais curto? O i = 1 é colocado na inicialização, e a condição é a mesma do while (i <= n); por fim, a atualização é i++, e ocorre depois de toda iteração. A lógica é a mesma do while, então não acho que tenha necessidade de explicar.

Fibonacci

Podemos calcular quantos termos quisermos da sequência de fibonacci com loops. Se você não sabe o que ela é, basicamente é uma sequência infinita que começa com 1, 1 e o  próximo termo é achado somando os dois anteriores, por exemplo, os primeiros 7 termos são: 1, 1, 2, 3, 5, 8, 13, .... Vamos fazer um programa que ache os primeiros N termos da sequência de fibonacci.

Primeiro vemos o caso de N = 0 e N = 1, já que nós começamos imprimindo 1, 1 na solução geral. Depois, para um N >= 2 fazemos o processo de guardar o penúltimo e o último termo da sequência, e então imprimimos a soma deles, e atualizamos o seus valores usando de uma variável auxiliar. Perceba que por mais que declaremos o i no for, não o usamos em momento algum no cálculo, mas sim somente para ter certeza que passamos por um número determinado de iterações (nesse caso passamos por N - 2 já que imprimimos 2 números logo no começo).

Comandos de Controle do Loop

Esses dois comandos servem para controlar o loop durante sua execução, e geralmente aparecem dentro de estruturas condicionais para em alguns casos específicos interromper o loop ou pular uma iteração. Ambos podem ser utilizados tanto no while quanto no for.

Break

Quando o comando break é encontrado dentro de um loop, ele interrompe imediatamente a execução desse loop e o programa continua a partir do próximo comando após o loop.  Por exemplo, no seguinte código:

O loop for segue até o i = 5 onde a execução do mesmo é finalizada, e a execução segue para o próximo comando (e como ele não existia o execução acaba). Note que caso o comando break viesse depois do cout a saída seria 0 1 2 3 4 5, já que o loop só seria finalizado após a impressão do 5.

Continue

O comando continue é usado para pular a iteração atual do loop e continuar com a próxima iteração, ignorando o restante do código dentro do loop para a iteração atual. Quando o continue é encontrado, o controle do loop é passado imediatamente para a próxima iteração. Segue um código de exemplo:

O loop for segue até o i = 5 onde a iteração é pulada, e a execução segue para a próxima iteração, ignorando o restante do código que continha a impressão. Note que caso o continue viesse após a impressão, a saída seria exatamente igual à aquela sem o continue, já que o mesmo se encontraria no final do código, e portanto não pularia nada na iteração do i = 5.

Extra - Loop dentro de loop

Esse assunto só vai ser usado quando você chegar na parte de matrizes do curso, mas irei explicar logo agora já que é parte do assunto de loops. Imagine que no planeta Nlog temos n horas em um dia, e m minutos em cada hora. Caso quiséssemos simular todos os horários dentro de um dia possíveis, como em um relógio digital, como faríamos? A maneira mais direta seria usando um loop dentro de outro loop. O código fica assim:

Ao rodar localmente e colocar a entrada como 3 5, por exemplo, você tem:

Assim, pode ficar mais fácil de perceber que um loop dentro de outro funciona da mesma forma que um relógio. O loop "interior" é como o ponteiro menor, e somente quando o loop interior dá uma "volta" completa uma iteração do exterior é concluída e a próxima começa, ou loop termina se não existe próxima.

Fim

Agora o universo de problemas que você  pode resolver se expandiu novamente, parabéns! Vá para página anterior e resolva os problemas recomendados para continuar sua jornada de aprendizado ?