MC102 |
PASSAGEM DE PARÂMETROS POR VALOR E REFERÊNCIA |
Até agora, tudo que podíamos fazer com procedimentos era passar valores a eles. Mas, e como retirar um valor deles?
Considere o seguinte exemplo: quero um procediemtno que, dadas 3 notas, tire sua média conforme a fórmula:
PROCEDURE media(n1,n2,n3 : real); VAR m : real; BEGIN m := (2*n1 + 3*n2 + 5*n3) / 10; write(m) END; |
Mas, e se quisermos usar o valor de m depois? Podemos fazê-lo global:
PROGRAM P; VAR m : real; PROCEDURE media(n1,n2,n3 : real); BEGIN m := (2*n1 + 3*n2 + 5*n3) / 10 END; BEGIN media(3.5,8,10); write(m) END. |
Funciona? Claro! MAs é horrível. Por que? Porque não é desejável que variáveis globais sejam modificadas dentro de procedimentos, pois, se tivermos dezenas de procedimentos em nosso programa, podemos nos confundir. Então o que faremos? Temos que ter um meio de calcular a média no procedimento e retirar o valor de lá. Como? Passando uma variável por referência:
PROGRAM P; 1. VAR m : real; 4. PROCEDURE media(n1,n2,n3 : real; VAR resp : real); BEGIN 5. resp := (2*n1 + 3*n2 + 5*n3) / 10 END; BEGIN 2. media(3.5,8,10,m); 3. write(m) END. |
Notou o VAR no parâmetro de "media"? Ele indica que a variável que segue a ele é passada por referência.
Como funciona um parâmetro por referência? Pense nele como uma variável local sem personalidade. Ela precisa de personalidade e, quando passamos a ela uma variável (como na linha 2. do programa acima), essa variável (no caso resp) assume a personalidade da variável passada (m). Ou seja, no nosso exemplo, tudo que fizermos com resp estaremos, na verdade, fazendo com m.
Vamos ver o diagrama de execução do programa:
1:
2:
5:
3:
Veja em 2 como representamos que resp recebeu m por referência: usamos uma seta indicando que qualquer mudança em resp será feita em m, o que de fato ocorre em 5, quando, ao darmos valor para resp, estamos dando para m.
Essa seta póde ser vista como resp apontando para seu chefe, m. Então quando queremos algo com resp e vamos a ela (para por exemplo, ler seu val.or ou guardar algo nela), resp diz: "Não é comigo, é com ela!" e aponta para m. Assim, ao lermos resp lemos m, e ao modificarmos resp, modificamos m.
Vamos ver um exemplo:
PROGRAM A; 1. VAR x,y : real; 2. a,b : integer; 3. PROCEDURE B(x : real; VAR y : integer); 4. VAR z : integer; BEGIN 5. z := Trunc(x / 2); 6. y := 2*z END; BEGIN 7. x := 3.1416; 8. B(x,a); 9. write(a); 10. y := 2*x; 11. B(x+y,b); 12. write(b) END. |
1 e 2:
7:
8, 3 e 4:
5:
6:
Note que modifiquei o "a".
9:
10:
11, 3 e 4:
5:
6:
12:
Estude atentamente os quadros acima e note que:
PROGRAM A; 1. VAR x : integer; 2. PROCEDURE B(VAR x : integer); BEGIN 3. x := 2 END; BEGIN 4. B(x); 5. write(x) END. |
B(2,2); B(2,x+a); etc |
B(x:int; VAR y: int; VAR z,a : real); |
PROGRAM A; VAR x : integer; PROCEDURE B(VAR n : integer); BEGIN n := (n * 5) MOD 3 END; BEGIN x := 4; B(x); write(x) {x = 2} END. |
Em B, pego o valor anterior de x, 4, multiplico por 5, pego o resto da multiplicação dividida por 3 e guardo em x.
Por fim, podemos chamar procedimentos de dentro de procedimentos, passando os parametros por referencia. Por exemplo:
1. PROGRAM A; 2. VAR x : integer; 3. PROCEDURE B(VAR n : integer); BEGIN 4. n := (n * 5) MOD 3 END; 5. PROCEDURE C(VAR m : integer); BEGIN 6. B(m); 7. m := m + 3 END; BEGIN 8. x := 4; 9. C(x); 10. write(x) {x = 5} END. |
Vamos fazer o diagrama de execuçao:
1 e 2 - o programa é definido:
8 - atualizo x:
9 e 5 - chamo C passando x por referência:
6 e 3 - chamo B passando m por referência. Note que, como m é uma encarnação de x, o que passo a B é x por referência:
4 - aqui é mais truculento. Primeiro devo pegar o valor de n e então fazer a conta e por em n novamente:
7 - modificamos m, modificando x:
10 - a saída é impressa: