MC102 |
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.