Tenho reparado ao longo dos anos que este é um ponto de confusão para os programadores iniciantes (e até para alguns experientes) e como perceber isto é algo absolutamente essencial num programador a sério (e para os outros também), lembrei-me de iniciar este documento. Vou aplicar isto a Pascal, mas a verdade é que o conceito é necessário em qualquer linguagem.
Para quem não sabe, nos procedimentos e funções permitem a passagem de parâmetros (valores ou variáveis), que serão inseridos no momento da chamada desse procedimento ou função, e serão transmitidos ao proprio código do procedimento ou função para por ele serem usados.
program parametro; var lado1,lado2:integer; function AreaRect(LadoMenor,LadoMaior:integer):integer; begin AreaRect:=LadoMenor*LadoMaior; end; begin Lado1:=6; Lado2:=4; Writeln(AreaRect(6,4),'cm2'); Writeln(AreaRect(Lado1,Lado2),'cm2'); end.
Resultado (o que aparece no ecrã):
24cm2 24cm2
Aqui, LadoMenor e LadoMaior são duas variáveis passadas por parâmetro. Isto significa que o compilador gera duas variáveis dentro da função AreaRect, com os nomes LadoMenor e LadoMaior, e que quando a função é chamada, preenche essas variáveis com os valores indicados entre parentesis aquando da chamada da função.
Neste caso, as variáveis podem ser usadas para qualquer fim dentro da função, e assumir qualquer valor do tipo indicado. No entanto, quando acaba a execução da função, qualquer valor que lá esteja é perdido.
Por exemplo:
program parametro; var valor1,valor2:integer; procedure DuplicaValores(v1,v2:integer); begin writeln('2º - Dentro: ',v1,' / ',v2); v1:=v1*2; v2:=v2*2; writeln('3º - Dentro: ',v1,' / ',v2); end; begin valor1:=6; valor2:=4; writeln('1º - Fora: ',valor1,' / ',valor2); DuplicaValores(valor1,valor2); writeln('4º - Fora: ',valor1,' / ',valor2); end.
Resultado:
1º - Fora: 6 / 4 2º - Dentro: 6 / 4 3º - Dentro: 12 / 8 4º - Fora: 6 / 4
Por aqui se pode ver que:
Portanto, isto mostra que a passagem por parâmetro é útil para enviar valores para dentro do procedimento, mas inútil para os trazer de dentro do procedimento para o local de chamada.
É aqui que entra a passagem por referencia.
A passagem por referência não cria duas variáveis com valores iguais aos que foram passados entre parentesis. O que ela faz é criar um atalho, dentro do procedimento ou função, para as variáveis originais. Deste modo, qualquer alteração feita dentro do procedimento é reflectida mesmo depois do procedimento ter terminado.
Para exemplo, fica o programa anterior, com apenas uma pequena alteração:
program parametro; var valor1,valor2:integer; procedure DuplicaValores(var v1,v2:integer); begin writeln('2º - Dentro: ',v1,' / ',v2); v1:=v1*2; v2:=v2*2; writeln('3º - Dentro: ',v1,' / ',v2); end; begin valor1:=6; valor2:=4; writeln('1º - Fora: ',valor1,' / ',valor2); DuplicaValores(valor1,valor2); writeln('4º - Fora: ',valor1,' / ',valor2); end.
Resultado:
1º - Fora: 6 / 4 2º - Dentro: 6 / 4 3º - Dentro: 12 / 8 4º - Fora: 12 / 8
Apenas colocando a palavra reservada VAR antes dos parâmetros do procedimento, indicamos ao compilador que as variáveis que se seguem são apenas atalhos para outras, e que deveram ter sempre o mesmo valor, tanto dentro como fora do procedimento ou função. Assim, o resultado final (4º) já depois de terminado o procedimento, manteve o valor multiplicado que se efectuou dentro do procedimento.
Isto obriga no entanto a que os valores que colocamos entre parentesis sejam variáveis.
Se com o procedimento indicado em cima usássemos…
DuplicaValores(6,4);
…o compilador iria dar erro, pois está à espera de variáveis que possam receber valores. Números absolutos e constantes não são permitidas por este motivo.
Do mesmo modo, usar na chamada uma variável, mas que não seja do mesmo tipo do declarado dentro do procedimento ou função, também iria ser gerado um erro:
program erro; var x:real; procedure teste(var y:integer); begin writeln(y); end; begin x:=5.15; teste(x); end.
Este código não iria funcionar. Daria um erro ao compilar, pois os tipos de variáveis são diferentes.
Existe uma terceira hipotese, embora seja na verdade apenas uma variante da passagem por parâmetros. A única diferença é que em vez do compilador criar variáveis dentro do procedimento ou função, cria constantes, o que significa que mesmo dentro do procedimento ou função os seus valores não podem ser alterados.
Espero que com isto seja mais fácil perceber a diferença e especialmente a importância destes conceitos para um programador. Se alguma duvida persistir, é só dizerem!