MC102
Algoritmos e Programação de Computadores
Parte XIV



Norton Trevisan Roman




PROCEDIMENTOS

Já vimos parte de procedimentos, agora vamos ver mais a fundo o que eles são e como usá-los. Mas, antes, é bom lembrarmos a principal razão de usarmos procedimentos: evitar código duplicado, tornando os programas menores e mais inteligíveis.

Considere o ovo se movendo. Como fazíamos isso? Tinhamos 2 procedimentos: apaga e desenha:

  PROCEDURE Desenha;        PROCEDURE Apaga;
  BEGIN                     BEGIN
    gotoxy(x+1,y);            gotoxy(x+1,y);
    write('*');               write(' ');
    gotoxy(x,y+1);            gotoxy(x,y+1);
    write('*');               write(' ');
    gotoxy(x,y+2);            gotoxy(x,y+2);
    write('*');               write(' ');
    gotoxy(x+1,y+3);          gotoxy(x+1,y+3);
    write('*')                write(' ')
  END;                      END;
        

São incrivelmente parecidas não? Não haveria um modo melhor de fazer isso? Claro! Note que o que fizemos foi imprimir "*" num procedimento e " " em outro. O que fazemos então? Passamos o caracter a ser impresso para dentro do procedimento. Como? Com parâmetros:

  PROCEDURE ovo(c : char);
  BEGIN
    gotoxy(x+1,y);
    write(c);
    gotoxy(x,y+1);
    write(c,' ',c);
    gotoxy(x,y+2);
    write(c,' ',c);
    gotoxy(x+1,y+3);
    write(c)
  END;
        

Agora, se quisermos desenhar o ovo chamamos:

  ovo('*');

  ou:

  ch := '*';
  ovo(ch);
	

Qualquer uma das duas maneiras vale. E para apagar?

  ovo(' ');

  ou:

  ch := ' ';
  ovo(ch);
	

Fácil, não? Agora você pode estar perguntando: em vez de parâmetro, c podia ser global, não? Sim, mas veja essa regrinha: evite variáveis globais. Por que? Porque em um programa grande você pode se confundir se começar a usar variáveis globais dentro de procedimentos. Use globais somente quando for usá-las no corpo do programa. Se algum procedimento as usar, passe como parâmetro.

Então, vamos melhorar nosso procedimento? Como? Arrancando as variáveis globais:

  PROCEDURE ovo(c : char; x,y : integer);
  BEGIN
    gotoxy(x+1,y);
    write(c);
    gotoxy(x,y+1);
    write(c,' ',c);
    gotoxy(x,y+2);
    write(c,' ',c);
    gotoxy(x+1,y+3);
    write(c)
  END;
	

Peraí, eu não mudei o código! Mudei sim!. Quando ovo acessa x e y no gotoxy, ele está acessando o x e o y dos parâmetros. Ao declarar um parâmetro com o mesmo nome de uma variável global, impeço o procedimento de enxergar essa global. Ou seja, para ovo, x e y são relativas aos parâmetros, ele não "enxerga" mais as globais x e y.

Lembra de nossa discussão sobre variáveis globais e locais? Pois é, parâmetros são um tipo de variáveis locais, ou seja, são vistas somente de dentro do procedimento, deixando invisível (de dentro deste procedimento) qualquer variável global que contenha o mesmo nome de alguma local.

quando o procedimento é chamado, o computador cria um espaço para ele, passando os parâmetros, e o executa. Vamos ver a animação do ovo:

  PROGRAM anima;
1.  CONST xin    = 10; {x inicial}
          yin    = 10; {y inicial}
	  numpos = 20; {número de posições que cairá}
2.  VAR cont : integer; {contador do for}

      PROCEDURE ovo(c : char; x,y : integer);
      BEGIN
        gotoxy(x+1,y);
        write(c);
        gotoxy(x,y+1);
        write(c,' ',c);
        gotoxy(x,y+2);
        write(c,' ',c);
        gotoxy(x+1,y+3);
        write(c)
      END;

    BEGIN
      {desenho o ovo}
3.    ovo('*',xin,yin);
4.    delay(500);

      {faço cair numpos posições}
5.    FOR cont := yin TO (yin + numpos - 1) DO
      BEGIN
        {apago o ovo}
6.      ovo(' ',xin,cont);
        {desenho uma posição abaixo}
7.      ovo('*',xin,cont+1);
8.      delay(500)
      END
    END.
	

Note que, ao passar valores aos parâmetros de ovo, posso dar o valor, como '*', dar uma variável, como xin, ou uma expressão, como cont+1. O que acontece é que o valor de cada um destes ('*', valor de xin e resultado de cont+1) é copiado para cada uma das variáveis dos parâmetros de ovo, em ordem, ou seja, na primeira chamada a ovo, as locais de ovo c, x e y recebem, respectivamente, '*', o valor de xin e o valor de yin.

Note também que delay nada mais é que um procedimento com um parâmetro.

Atenção!
Se você fizer isso:

  PROCEDURE ovo(c : char; x,y : integer);
  BEGIN
    ...
    c := 'a';
    ...
  END;
	

você mudou o valor da variável local c, ou seja, o que foi passado no parâmetro foi perdido.



DIAGRAMAS DE EXECUÇÃO

Agora vamos fazer um diagrama de execução para nosso programa do ovo. Um o que? O diagrama de execução mostra o estado das variáveis do programa. Veja o exemplo com o ovo. Primeiro crio um diagrama para o programa, com variáveis e constantes (nesse caso, fiz numpos=2, para ficar mais rápido):

Começo a execução do programa e, como na linha 3 chamamos um procedimento, crio novo diagrama para ele, dando valor aos parâmetros:

agora executamos ovo, marcando sua saída. Note que nenhum parâmetro foi mudado.

na linha 4, o delay não é um procedimento meu, então não represento. Na linha 5 atualizo o contador:

na linha 6, chamo novamente o procedimento:

nas linhas 7 e 8 desenho novamente o ovo, uma posição abaixo e espero um momento:

voltando ao FOR na linha 5:

passando novamente pela linha 6:

linhas 7 e 8:

incrementa o contador e faz o teste do FOR, como passou do limite, sai do FOR, saindo do programa:

Isso é um diagrama de execução. Vejamos com outro exemplo:

  PROGRAM A;
  VAR x,y : real;

      PROCEDURE B(z : real);
      VAR h : real;
      BEGIN
        h := z * 5;
	writeln('B: ',h)
      END;

  BEGIN
0.  y := 3;
1.  x := y + 2;
2.  y := x * y;
3.  B(y);
4.  B(x)
  END.
	

Vamos executar: crio um diagrama com o nome do programa e suas variáveis (e constatnes se houver). Começo a rodar do BEGIN (linha 0):

linha 1:

linha 2:

linha 3:

mudo o valor de h, no procedimento:

linha 4:

mudo o valor de h, no procedimento:

Naturalmente, você deve fazer todos os desenhos num só. As figuras mostram apenas a evolução temporal do diagrama.

Para ver mais sobre diagramas consulte as notas sobre passagem de parâmetros.





‹— Parte XIIIPágina da disciplinaParte XV —›