Linguagem C Básico Aula 07: Laços com número de repetições Indeterminado

 

Símbolo do infinito
O Símbolo de infinito também é um laço sem fim

Recapitulando

    No curso de algoritmos vimos que existem estruturas de controle de fluxo conhecidas como laços de repetição que permitem que o programa execute as mesmas instruções por mais de uma vez. Já na aula passada vimos dois comandos na linguagem C que permitem a criação de laços repetição.

    No entanto os exemplos que foram mostrados abordavam os chamados laços de repetição com número de repetições determinado, isto é, o programa executa as mesma instruções por um determinado número de vezes e depois sai do laço seguindo o fluxo normal. Para isso vimos o comando for() e o while() com o uso de contadores. 

    Na aula passada também expliquei que o for() era mais utilizado para essa situação, pois foi criado exatamente para isso. Hoje veremos as situações onde o while() é mais utilizado e para isso vamos retomar o problema que coloquei na aula passada:

    Como fazer o programa de cálculo de média de um aluno visto nas últimas aulas calcular a média de vários alunos de uma sala? Detalhe: Eu não sei quantos alunos tem sala! Já entendeu onde eu quero chegar?

Laços de Repetição com número de repetições indeterminado

    O título do tópico já diz como solucionar o problema do programa de média. Eu preciso criar um laço que faça o programa executar as instruções de cálculo de média e depois repeti-las por um número de vezes indeterminado, mas onde começa e termina esse laço?

    Para responder isso vamos rever o último programa da aula de ifs encadeados:

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     float nota1,nota2,media;
  5.     int frequencia;
  6.     printf("Digite a nota1: "); 
  7.     scanf("%f",&nota1);  
  8.     printf("Digite a nota2: ");
  9.     scanf("%f",&nota2);
  10.     printf("Digite a %% de Frequência: ");
  11.     scanf("%d",&frequencia);
  12.     media=(nota1+nota2)/2;
  13.     printf("Média Final: %.1f\n",media); 
  14.     if (media>=5 && frequencia>=75){
  15.         printf("Aluno foi Aprovado!");
  16.     }
  17.     else{
  18.         if (frequencia>=75){
  19.             printf("Aluno para recuperação!");
  20.         }
  21.         else{
  22.             printf("Aluno foi Reprovado por frequência!");
  23.         }
  24.     }
  25.     return 0;
  26. }

    Olhando o programa o que você acha que precisa ser repetido toda vez que for calcular a média dos vários alunos? Se você respondeu a linha 7 acertou. Porque pra todos os alunos você vai precisar digitar a nota1. Então ai será o início do nosso laço.

    Você poderia ter dúvidas se o laço deveria começar um pouco mais acima, mas o que vemos no programa são as criações das variáveis e você não precisa criar variáveis para cada aluno. Pode utilizar a mesma. Até ai tudo bem, mas como eu farei o laço?

    Vamos lembrar que a estrutura do laço while() é geralmente assim:

    while(condição a ser satisfeita){
        instruções a serem feitas em uma ou mais linhas;
    }

    Sendo assim, eu preciso pensar em uma condição a ser satisfeita, mas podemos utilizar a estratégia que aprendemos no curso de algoritmos usando o chamado "enquanto for verdadeiro". O que era isso mesmo? Era uma estrutura assim:


 enquanto(verdadeiro){
        instruções a serem feitas em uma ou mais linhas
    }

    Isso fazia o programa executar um laço infinito sem parar até o programa ser interrompido a força, mas aqui na linguagem C temos recursos para interromper esse tipo de laço. Então vamos começar a passar essa estratégia para a linguagem C.  Lembrando que na linguagem C 1 é o valor que representa dado booleano verdadeiro e 0 representa o booleano falso. Dessa forma o laço ficaria assim:

     while(1){
        //instruções do programa anterior
    }

    Bom mas agora como eu interrompo o laço? Vamos relembrar um fluxograma visto no curso de algoritmo. Ele não é exatamente o nosso problema, mas dá uma ideia do que precisamos:


Fluxograma mostrando um laço indeterminado controlado por uma resposta
Fluxograma mostrando um laço indeterminado controlado por uma resposta

    Pelo fluxograma, poderíamos perguntar para o usuário se ele deseja interromper o programa respondendo S para sim ou N para não. Se eu vou armazenar a respostas do usuário, precisarei de uma variável char para isso. Se eu vou testar a resposta do usuário precisarei de um if() para isso.

    Isso deu bastante dicas. Assim vamos precisar incluir algo assim no programa:


    char resposta;
    while(1){
        //instruções do programa anterior
        printf("\nInterromper o programa?");
        scanf("%c",&resposta);
        if (resposta=='s'){
            break;
        }
    }

   Repare que eu coloquei um \n na pergunta sobre interrupção para ela não ficar grudada com o que estiver acima dela. A novidade aqui foi o comando break que NÃO vimos no Portugol. Ele é uma novidade aqui da Linguagem C que serve para quebrar o laço e interromper a sua execução. 

    Vamos ver só esse pedacinho funcionando? Copie e cole o código abaixo no GDB Online e teste respondendo com várias letras diferentes além do 's' só pra ver como ele funciona:


  1. #include <stdio.h>

  2. int main()
  3. {
  4.     char resposta;
  5.     while(1){
  6.         //instruções do programa anterior
  7.         printf("\nInterromper o programa?");
  8.         scanf("%c",&resposta);
  9.         if (resposta=='s'){
  10.             break;
  11.         }
  12.     }
  13.     return 0;
  14. }
    Viu o laço funcionando? Ele repetiu a pergunta várias vezes? Testou com várias letras? Se você testou bem, deve ter reparado dois problemas. O primeiro é que, em alguma vezes, temos a impressão que ele executa duas vezes a pergunta. Como se alguém tivesse pressionado o enter. Reparou?

Exemplo de buffer de teclado
Exemplo de buffer de teclado

    Esse defeito é o que chamamos de "buffer de teclado" e ocorre quando damos um ENTER no scanf(), pois o ENTER além de ser a tecla que finaliza a entrada também representa uma quebra de linha. É como se ele fosse lido duas vezes. 

    Uma forma simples de resolver isso é incluir um espaço em branco na string de especificação de formato do scanf(), isto é, ao invés de usar "%c" eu uso " %c". Esse espaço faz o C desconsiderar o enter.

Buffer de teclado resolvido
Buffer de teclado resolvido


    Outra coisa, reparou que ele NÃO interrompe se você responde 'S' maiúsculo. Vamos corrigir também essa falha? Teste agora:

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     char resposta;
  5.     while(1){
  6.         //instruções do programa anterior
  7.         printf("\nInterromper o programa?");
  8.         scanf(" %c",&resposta);
  9.         if (resposta=='s' || resposta=='S'){
  10.             break;
  11.         }
  12.     }
  13.     return 0;
  14. }

    O que fizemos foi incluir no if() da linha 10 uma condição dupla do tipo OU || . Isto significa que, se a resposta for 's' ou se a resposta for 'S' a condição é verdadeira. Lembrando que com o operador OU se um condição for verdadeira a outra nem será considerada.

    Portanto já temos praticamente a solução quase montada, mas precisamos saber onde entrará esse código todo. O while a gente já viu que vai entrar na linha 7 e agora teremos que incluir também acima dela a declaração da variável caracter resposta

    Veja que depois do while(1){ temos as instruções do programa anterior que é praticamento todo o resto do programa até o return 0. Então o restante do código entraria antes desse return. Assim, temos o seguinte código que eu vou indentar para ficar mais fácil de entender:

  1. #include <stdio.h>

  2. int main()
  3. {
  4.     float nota1,nota2,media;
  5.     int frequencia;
  6.     char resposta;
  7.     while(1){
  8.         printf("Digite a nota1: "); 
  9.         scanf("%f",&nota1);  
  10.         printf("Digite a nota2: ");
  11.         scanf("%f",&nota2);
  12.         printf("Digite a %% de Frequência: ");
  13.         scanf("%d",&frequencia);
  14.         media=(nota1+nota2)/2;
  15.         printf("Média Final: %.1f\n",media); 
  16.         if (media>=5 && frequencia>=75){
  17.             printf("Aluno foi Aprovado!");
  18.         }
  19.         else{
  20.             if (frequencia>=75){
  21.                 printf("Aluno para recuperação!");
  22.             }
  23.             else{
  24.                 printf("Aluno foi Reprovado por frequência!");
  25.             }
  26.         }
  27.         printf("\nInterromper o programa?");
  28.         scanf(" %c",&resposta);
  29.         if (resposta=='s' || resposta=='S'){
  30.             break;
  31.         }
  32.     }
  33.     return 0;
  34. }

  Você deve ter achado difícil encontrar o ponto onde o código devia ser inserido e isso é normal quando temos várias linhas com instruções. Mais tarde, quando aprendermos a criar funções na linguagem C, esse tipo de situação ficará mais fácil.


Próxima Aula                                                                                                                        Aula Anterior

Referências

DAMAS, L. Linguagem C. Rio de Janeiro: LTC Editora, 2007.

GBD ONLINE. C for Beginners. Disponível em: <https://learn.onlinegdb.com/c_for_beginners> Acesso em 05 ago. 2024.

GBD ONLINE. C Programming Examples Disponível em: <https://learn.onlinegdb.com/c_program_examples> Acesso em 05 ago. 2024.

W3SCHOOLS. C Tutorial. Disponível em: <https://www.w3schools.com/c/index.php> Acesso em 05 ago. 2024.