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