Introdução ao conceito de parâmetros para funções

Neste texto, explicamos os princípios a respeito de passagem de parâmetros para funções, particularmente diferenciando as passagens por referência (ou endereço) e por valor.

Por que parâmetros são necessários para funções?

A passagem de parâmetros é essencial para ampliar o potencial de uso de uma função. Uma função sem parâmetro, é apenas um procedimento que executará sempre exatamente os mesmos passos. Por exemplo, uma função para computar o fatorial de um número natural, deve ter um único parâmetro, digamos n, sendo que n deve conter o valor para o qual deseja-se saber o fatorial. Por um lado, na declaração da função deve-se indicar de alguma forma este parâmetro, que neste caso é denominado parâmetro formal (por ser um formalismo necessário para funcionar o conceito).
Por outro lado, o ponto do código que "está interessado" no fatorial de algum valor é quem deve invocar a função passando-lhe esse valor como parâmetro, que neste caso recebe o nome de parâmetro efetivo (pois é efetivamente o valor sobre o qual dever ser "aplicada" a função).


Fig. 1. Ilustração do fluxo de execução ao invocar uma função para computar o fatorial de um natural.

A figura 1 ilustra o exemplo da função fatorial, o código à esquerda está interessado em computar o fatorial de N, de k e de N-k, que são os parâmtros efetivos para a função fat do exemplo. Do lado direito está a código da função, sua declaração (usamos o nome fat) e seu único parâmtro formal, que recebeu o nome n.

Introdução aos parâmetros formal e efetivo

O conceito de funções apresenta 4 palavras-chave principais, que são:

Assim, no caso de passagem de parâmetro por referência (ou por endereço), como o nome indica, será passada uma referência à uma variável externa à função (o parâmetro efetivo). Desse modo, dentro da função, ao alterar o valor do parâmetro formal, quem estará sendo alterado é efetivamente à variável externa. Em C existe uma sintaxe especial para declarar e alterar o parâmetro por referência (usando asterisco '*' - vide exemplo abaixo).

Já o uso de parâmetro por valor é mais simples, o parâmetro formal funciona como uma variável local que é inicializada com o valor do parâmetro efetivo, assim que a função em questão é invocada. Qualquer alteração do parâmetro formal, tem influência nula sobre o parâmetro formal associado (ou seja, uma atribuição dentro da função com determinado parâmetro, não provoca alteração alguma no valor da variável que foi passada para a função - parâmetro efetivo).

Nos exemplos abaixo ilustramos os 4 conceitos em exemplos para C e para Python.

CPython
int soma (int a, int b) {
  int c = a+b; // variavel local: sem relacao com 'main.c'!
  return a+b; // devolve a+b
  }
int soma_max (int a, int b, int *max) {
  if (a < b)
    *max = b; // altera o valor da referencia (em quem invocou soma_max)
  else 
    *max = a; // em caso de empate tanto faz...
  return a+b; // devolve a+b
  }
int main (void) {
  int a, b, c, maximo;
  scanf("%d %d", &a, &b); // operador '&' pega o endereco da variavel na memoria
  c = soma_max(a,b,&maximo);
  print("Soma de %d e %d = %d = %d.\n", a, b, soma(a,b), c);
  print("O maximo e': %d\n", maximo);
  return 1;
  }
def soma (a, b) :
  c = a+b; # variavel local: sem relacao com 'main.c'!
  return a+b; # devolve a+b

def soma_max (a, b, max) :
  if (a < b) :
    max[0] = b; # altera o valor da referencia (em quem invocou soma_max)
  else :
    max[0] = a; # em caso de empate tanto faz...
  return a+b; # devolve a+b

def main () :
  a = int(input());
  b = int(input());
  maximo = []; maximo.append(-1); # truque: usar vetor para param. por ref.
  c = soma_max(a, b, maximo);
  print("Soma de %d e %d = %d = %d." % (a, b, soma(a,b), c));
  print("O maximo e': %d" % (maximo[0]));

main();

Explicações sobre as diferenças entre parâmetros por referência e por valor

A diferença entre passagem de parâmetro por referência ou valor, no primeiro caso é passado o endereço (ou referência) da variável efetivamente usada (parâmetro efetivo) e no segundo o valor da variável efetivamente usada apenas serve como valor inicial para o parâmetro formal (uma inicialização).

C: No código C acima, o que definiu tratar-se de referência foi o uso de '*' no parâmetro formal. Além disso, para fazer referência ao parâmetro efetivo (a variável maximo) também foi preciso usar o '*'.
Por outro, na chamada da função foi preciso passar o endereço da variável maximo e isso foi possível usando o operador '&'.
No exemplo não aparece, mas em C, ao passar um vetor como parâmetro, automaticamente ele é passador por referência.
Para examinar mais sobre funções em C clique aqui.

Python: No código Python acima, o que definiu tratar-se de referência foi usar como parâmetro formal um vetor (ou lista). Por isso foi preciso o "truque" de definir um vetor (de nome maximo, com um único elemento) e passá-lo como parâmetro efetivo para a função.
Assim, em Python, sempre que passar um vetor como parâmetro, automaticamente ele é passador por referência.
Para examinar mais sobre funções em Python clique aqui.

Leônidas de Oliveira Brandão
http://line.ime.usp.br

Alterações:
2020/08/20: acertos no formato
2020/08/10: revisão de formato e nova introdução
2020/08/09: Sábado, 09 de Agosto 2020, 14:00
2018/04/24: Terça, 24 de Abril 2018, 12:30
2011/06/10: inicial