Podemos dizer que uma passagem de parâmetros por referência pode

CURSO DE C

 

Podemos dizer que uma passagem de parâmetros por referência pode

Passagem de par�metros por valor e passagem por refer�ncia

J� vimos que, na linguagem C, quando chamamos uma fun��o os par�metros formais da fun��o copiam os valores dos par�metros que s�o passados para a fun��o. Isto quer dizer que n�o s�o alterados os valores que os par�metros t�m fora da fun��o. Este tipo de chamada de fun��o � denominado chamada por valor. Isto ocorre porque s�o passados para a fun��o apenas os valores dos par�metros e n�o os pr�prios par�metros. Veja o exemplo abaixo:

#include <stdio.h>
float sqr (float num);
void main ()
{
	float num,sq;
	printf ("Entre com um numero: ");
	scanf ("%f",&num);
	sq=sqr(num);
	printf ("\n\nO numero original e: %f\n",num);
	printf ("O seu quadrado vale: %f\n",sq);
}

float sqr (float num)
{
	num=num*num;
	return num;
}

No exemplo acima o par�metro formal num da fun��o sqr() sofre altera��es dentro da fun��o, mas a vari�vel num da fun��o main() permanece inalterada: � uma chamada por valor.

 Outro tipo de passagem de par�metros para uma  fun��o ocorre quando altera��es nos par�metros formais, dentro da fun��o, alteram os valores dos par�metros que foram passados para a fun��o. Este tipo de chamada de fun��o tem o nome de "chamada por refer�ncia". Este nome vem do fato de que, neste tipo de chamada, n�o se passa para a fun��o os valores das vari�veis, mas sim suas refer�ncias (a fun��o usa as refer�ncias para alterar os valores das vari�veis fora da fun��o).

 O C s� faz chamadas por valor. Isto � bom quando queremos usar os par�metros formais � vontade dentro da fun��o, sem termos que nos preocupar em estar alterando os valores dos par�metros que foram passados para a fun��o. Mas isto tamb�m pode ser ruim �s vezes, porque podemos querer mudar os valores dos par�metros fora da fun��o tamb�m. O C++ tem um recurso que permite ao programador fazer chamadas por refer�ncia. H� entretanto, no C, um recurso de programa��o que podemos usar para simular uma chamada por refer�ncia.

 Quando queremos alterar as vari�veis que s�o passadas para uma fun��o, n�s podemos declarar seus par�metros formais como sendo ponteiros. Os ponteiros s�o a "refer�ncia" que precisamos para poder alterar a vari�vel fora da fun��o. O �nico inconveniente � que, quando usarmos a fun��o, teremos de lembrar de colocar um & na frente das vari�veis que estivermos passando para a fun��o. Veja um exemplo:

#include <stdio.h>
void Swap (int *a,int *b);
void main (void)
{
	int num1,num2;
	num1=100;
	num2=200;
	Swap (&num1,&num2);
	printf ("\n\nEles agora valem %d  %d\n",num1,num2);
}
void Swap (int *a,int *b)
{
	int temp;
	temp=*a;
	*a=*b;
	*b=temp;
}

N�o � muito dif�cil. O que est� acontecendo � que passamos para a fun��o Swap o endere�o das vari�veis num1 e num2. Estes endere�os s�o copiados nos ponteiros a e b. Atrav�s do operador * estamos acessando o conte�do apontado pelos ponteiros e modificando-o. Mas, quem � este conte�do? Nada mais que os valores armazenados em num1 e num2, que, portanto, est�o sendo modificados!

Espere um momento... ser� que n�s j� n�o vimos esta est�ria de chamar uma fun��o com as vari�veis precedidas de &? J�! � assim que n�s chamamos a fun��o scanf(). Mas porqu�? Vamos pensar um pouco. A fun��o scanf() usa chamada por refer�ncia porque ela precisa alterar as vari�veis que passamos para ela! N�o � para isto mesmo que ela � feita? Ela l� vari�veis para n�s e portanto precisa alterar seus valores. Por isto passamos para a fun��o o endere�o da vari�vel a ser modificada!


AUTO AVALIA��O

Veja como voc� est�:
  Escreva uma fun��o que receba duas vari�veis inteiras e "zere" o valor das vari�veis.  Use o que voc� aprendeu nesta p�gina para fazer a implementa��o


Podemos dizer que uma passagem de parâmetros por referência pode

 
Podemos dizer que uma passagem de parâmetros por referência pode
 
Podemos dizer que uma passagem de parâmetros por referência pode

Curso de C do CPDEE/UFMG - 1996 - 1999

Origem: Wikilivros, livros abertos por um mundo aberto.

Variáveis de referência[editar | editar código-fonte]

Em C++ podemos criar variáveis que podem ser uma alternativa para os ponteiros em algumas situações. A vantagem de não usar diretamente o endereço (valor de ponteiro) em situações onde não precisamos lidar diretamente com valores de memória torna a programação mais segura e simplificada. Podemos deixar as operações com ponteiros apenas para quando for estritamente necessário.

Variáveis de referência podem ser criadas para dar um nome diferente para as variáveis que já existem no programa, ou para passar a variável para dentro do corpo de uma função. Observemos, inicialmente, um caso simples:

  int  a = 10;
  int &b = a;

  b = 20;

Neste trecho de programa, criamos uma variável de referência b para a variável a, o que significa que criamos outro nome para a variável a. De fato, b é a própria variável a com outro nome, apenas isso. Desta forma, podemos alterar o valor de a usando b.

Passagem de parâmetros[editar | editar código-fonte]

Na linguagem "C", durante a chamada de uma função, os argumentos (parâmetros) têm seus valores copiados para a área de processamento da função. Depois que os mesmos foram usados dentro do bloco de processamento da função, eles são descartados. A função retorna o processamento para o bloco que a chamou trazendo apenas o valor de retorno. A única maneira de fazer com que a função modifique o valor de alguma variável definida no bloco de programa que a chamou é passá-la por um ponteiro com o seu endereço.

Vejamos o fragmento de código seguinte:

       int f( int x ) 
          {
           x--;
           return x;
          }

       int main()
          {
           int a = 10;
           int b;

           b = f(a);
           ...
           ...

Em "C", a menos que o programador seja bem malicioso e faça manipulações de memória arriscadas, a função f jamais alterará o valor do seu argumento x.

Diferentemente da linguagem "C", a chamada a uma função em C++ pode alterar o valor de uma variável definida antes da chamada da função, mesmo sem esta variável ser explicitamente passada como um ponteiro. Este modo é chamado de passagem por referência. Em termos mais gerais, significa a passagem da variável propriamente dita, para o corpo interno da função com outro nome, aquele definido na lista de parâmetros da função.

Em C++, uma função pode ser chamada na forma acima e alterar o valor das suas variáveis. Para isso basta declará-la como:

  int f(int & x) 
  {
    x--;
    return x;
  }

Temos em C++ o operador & que se comporta analogamente do mesmo em C, porém tendo uma função a mais, a de criar variáveis de referência:

  • &x quando usado no código retorna o pointero para o endereço de x;
  • &x quando usado na declaração de variável, cria uma referência;
  • &x quando usado como parâmetro na declaração de uma função faz com que suas chamadas transfira o argumento/parâmetro passando-o de forma similar a passagem de seu ponteiro. (Passagem por referência).

Em termos semânticos, ao passar a variável para uma função onde o parâmetro é uma referência, o endereço da variável é atribuído ao endereço do parâmetro. Desta forma, o parâmetro é a mesma variável passada, no trecho de código onde a função foi invocada, assumindo um nome diferente dentro da função. Podemos dizer que a variável assume um apelídio dentro da função, sendo a mesma com nome diferente apenas.

Vejamos um exemplo usando a função anterior:

  int m = 4;
  f(m);
  cout << m << endl;

O código anterior imprime na saída padrão o valor 3. Acompanhando o fluxo de execução verificamos o seguinte: Depois que a variável m é incluída na chamada da função o seu nome muda para x e o programa passa a ser executado dentro da função, onde a variável é decrementada. Portanto, quando a execução retorna para o corpo principal a variável estará decrementada.

Exemplo: alterando o valor da variável usando referência[editar | editar código-fonte]

 #include <iostream>
 using namespace std;
 int main()
 {
    int val = 1;
    int &ref = val;
    cout << "val is " << val << endl;
    cout << "ref is " << ref << endl;
    cout << "Setting val to 2" << endl;
    val = 2;
    cout << "val is " << val << endl;
    cout << "ref is " << ref << endl;
    cout << "Setting ref to 3" << endl;
    ref = 3;
    cout << "val is " << val << endl;
    cout << "ref is " << ref << endl;
    cout<<"Digite enter para continuar..."<<endl;
    cin.get();
    return 0;
 }

Como se viu conseguimos alterar o valor de val alterando o valor de ref.

Existe apenas umas restrições para o seu uso:

  • Teremos de inicializar e no momento da declaração teremos de atribuir de imediato o valor (se não fizermos isso gerará um erro de compilação)
  • As referência não podem ser reatribuídas, ou seja no exemplo anterior tinha

int &ref = val; se mais tarde no código tentar-se fazer int &ref=m; (sendo m uma variável já declarada e iniciada por hipótese) o que acontece é que a 2ª instrução é completamente ignorada e ficamos sempre com a primeira.

A vantagem real das referências é que quando elas são usadas para passar valores para as funções elas providenciam uma maneira de retornar valores das funções.

Vejamos o exemplo

 #include <iostream>
 using namespace std;
 int main()
 {
    int val1 = 10;
    int val2 = 20;
    int &ref = val1;
    cout << "val1 is " << val1 << endl;
    cout << "val2 is " << val2 << endl;
    cout << "ref is " << ref << endl;
    ref = val2;    //What does this do?
    cout << endl << "ref = val2" << endl;
    cout << "val1 is " << val1 << endl;
    cout << "val2 is " << val2 << endl;
    cout << "ref is " << ref << endl;
    val2 = 30;
    cout << endl << "Setting val2 = 30" << endl;
    cout << "val1 is " << val1 << endl;
    cout << "val2 is " << val2 << endl;
    cout << "ref is " << ref << endl;
    cout<<"Digite enter para continuar..."<<endl;
    cin.get();
    return 0;
 }

Exemplo: Swap[editar | editar código-fonte]

O exemplo abaixo mostra uma forma muito comum de usar referências. A instrução "swap", que tem por objetivo trocar os valores de duas variáveis, é mais naturalmente chamada como Swap(a, b) do que Swap(&a, &b); assim, é mais simples declarar a função usando referência:

 #include <iostream>
 using namespace std; 
 void Swap (int &i,int &j)
  {
 	int t=i;
 	i=j;
 	j=t;
  }
  int main ()
  {
 	int a,b; 
 	a=5;
 	b=10;
 	cout<<a<<"\t"<<b;
 	Swap (a,b);
 	cout<<a<<"\t"<<b;
        cout<<"Digite enter para continuar..."<<endl;
        cin.get();
     	return 0;
  }

Comparação entre passagem por referência e ponteiros[editar | editar código-fonte]

Para exercitar vamos criar um novo problema: Criar um função que duplique qualquer valor colocado pelo utilizador:

1º PROGRAMA-via referência 2º PROGRAMA – via ponteiros - endereços

 #include <iostream>
 using namespace std;
 void doubleIt(int&);//prototype com endereço de variavel
 int main ()
 {
   int num;
   cout << "Enter number: ";
   cin >> num;
   cin.get();
   doubleIt(num);	//chamo função, passando parametro num
   cout << "The number doubled in main is " << num << endl;
   cout<<"Digite enter para continuar..."<<endl;
   cin.get();
   return 0;
 }
 void doubleIt (int& x)	 	
 {
   cout << "The number to be doubled is " << x << endl;
   x *= 2;
   cout << "The number doubled in doubleIt is " << x << endl;
 }

 #include <iostream>
 using namespace std;
 void doubleIt(int*);  //parametro por endereço
 int main ()
 {
   int num;
   cout << "Enter number: ";
   cin >> num;
   cin.get();
   doubleIt(&num);//passei parametro como endereço
   cout << "The number doubled in main is " << num << endl;
   cout<<"Digite enter para continuar..."<<endl;
   cin.get();
   return 0;
 }
 void doubleIt (int* x)
 {
   cout << "The number to be doubled is " << *x << endl;
   *x *= 2;
   cout << "The number doubled in doubleIt is " << *x << endl;
 }

Ou seja, nestes dois códigos temos uma passagem por referência e outro por endereço. Com diferenças:

  • Na chamada da função (dentro do main() )
doubleIt(num);   // por referência
doubleIt(&num);  // por endereço
  • No protótipo da função (confirmar o ponto e virgula)
void doubleIt(int&);  // por referência
void doubleIt(int*);  // por endereço
  • No "header" da função
void doubleIt (int& x)   // por referência
void doubleIt (int* x)   // por endereço
  • dentro do corpo da função (dentro da própria função)
x
*x

Podemos pensar que passando por referência parece ser muito mais simples do que passado por endereço.

Na verdade existem certas funções da biblioteca que só permitem a passagem por endereço.

O que é passagem de parâmetros por referência?

Na Passagem de Parâmetro por Referência passamos todo o endereço do argumento para o parâmetro. Devido a isto, qualquer alteração feita no parâmetro afeta a variável usada para chamar a função, pois dentro da função é usado o endereço real do argumento para acessá-lo na hora da chamada da função.

Quais são os tipos de passagem de parâmetros?

Tipos de parâmetros: existem duas formas de passar parâmetros para as funções e procedimentos – passagem por valor (só envia valores) e passagem por referência (permite enviar e também receber valores).

Como passar parâmetro por referência em Python?

Em Python o que é necessário fazer para isso acontecer? A ideia é ter uma variável definida no inicio do programa, alterar ela dentro da função, e mudar o valor dela fora da função sem usar return . Se a ideia é alterar o valor de uma variável externa, use o return e atribua novamente à variável.

Como Passar valores por referência em C?

Na linguagem C a passagem por referência é implementada com o uso de ponteiros. Usando ponteiros (também chamados de apontadores) é possível alterar os valores das variáveis passadas como argumentos para uma função. A função utilizada dessa forma é denominada função com passagem por referência.