Monday, 29 October 2012

Functions: Passing Value and Pass Reference

Pass by value and pass by reference (and reference variables)

Pass by value and Pass by Reference

We have seen as to how to pass values to a function through arguments. Actually there are two ways to pass values to a function through arguments. These two methods are explained below with examples.
Pass By Value:
Example:
void check (int x)
{
//body of function
}
int main ( )
{
int b = 10;
check (b);
}

In this function, ‘x’ is a parameter and ‘b’ (which is the value to be passed) is the argument. In this case the value of ‘b’ (the argument) is copied in ‘x’ (the parameter). Hence the parameter is actually a copy of the argument. The function will operate only on the copy and not on the original argument. This method is known as PASS BY VALUE. So far we have dealt only with pass by value (except when passing arrays to functions).
// Pass by value illustration
#include <iostream.h>
int square (int x)
{
return x*x;
}
int main ( )
{
int num = 10;
int answer;
answer = square(num);
cout<<"Answer is "<<answer; // answer is 100
cout<<" Value of a is "<<num; // num will be 10
return 0;
}

You can see that the value of ‘num’ is unchanged. The function ‘square’ works only on the parameter (i.e. on x ). It does not work on the original variable that was passed (i.e it doesn't work on ‘num’).
The diagram makes it quite clear as to what happens when we call square(num). The following initialization takes place:
            int x = num;
and the function square( ) operates only on a copy of num.

Pass By Reference

In pass by reference method, the function will operate on the original variable itself. It doesn't work on a copy of the argument but works on the argument itself. Consider the same square function example:
// Illustration of pass by reference
#include <iostream.h>
void square (int *x)
{
*x = (*x) * (*x);
}

int main ( )
{
int num = 10;
square(&num);
cout<<" Value of num is "<<num; // Value of num is 100
return 0;
}

As you can see the result will be that the value of a is 100. The idea is simple: the argument passed is the address of the variable ‘num’. The parameter of ‘square’ function is a pointer pointing to type integer. The address of ‘num’ is assigned to this pointer. You can analyze it as follows: &num is passed to int *x, therefore it is the same as:
int *x = &num;
This means that ‘x’ is a pointer to an integer and has the address of the variable num.
Within the function we have:

*x = (*x) * (*x);

* when used before a pointer will give the value stored at that particular address. Hence we find the product of ‘num’ and store it in ‘num’ itself. i.e. the value of 100 is stored in the address of ‘num’ instead of 10 which was originally present there. The diagram below illustrates the difference between pass by value and pass by reference. Now when we dereference ‘x’ we are actually manipulating the value stored in ‘num’.
This is the pass-by-reference method which was used in C. In C++ there is a different approach. Of course you can use the above method, but C++ has its own special way.




aliases: Pass by value

From clc-wiki

Pass by value is a term describing function call semantics. To pass by value means that the argument (a variable, constant or other expression) is evaluated and a copy of its value is then passed to the function.
Whenever the function accesses the parameter it receives, it does so without reference to the original argument which cannot be overwritten; nor can a volatile argument change the value of the parameter once the function is entered. Pass by value semantics can be contrasted with pass by reference semantics, which C does not directly support.

Quick examples

The program below
#include <stdio.h>
void foo(int x);

int main(void) {
  int i = 5;
  
  printf("In main(): %d\n", i);
  foo(i);
  printf("In main(): %d\n", i);

  return 0;
}

void foo(int x) {
  printf("In foo(): %d\n", x);
  x = 10;
  printf("In foo(): %d\n", x);
}
prints
 In main(): 5
 In foo(): 5
 In foo(): 10
 In main(): 5







From clc-wiki

Pass by reference is a term that describes a part of the semantics of function parameters. To pass by reference means that within the function, the formal parameter is or acts as an alias (reference) for the function argument - so pass by reference is only meaningful when the function's argument is a variable (note that "parameter" and "argument" have slightly different meanings - consult the link in the "See Also" section below).
Within the function, accesses of the formal parameter, either for reading or for writing, directly access the same variable that the caller of the function passed in as its argument.
C does not directly support pass by reference because it always uses pass by value, but a programmer can implement pass by reference by passing a pointer to the variable that the programmer wants passed by reference.

Quick examples

The program below
#include <stdio.h>
void foo(int *x);

int main(void) {
  int i = 5;
  
  printf("In main(): %d\n", i);
  foo(&i);
  printf("In main(): %d\n", i);

  return 0;
}

void foo(int *x) {
  printf("In foo(): %d\n", *x);
  *x = 10;
  printf("In foo(): %d\n", *x);
}
prints
 In main(): 5
 In foo(): 5
 In foo(): 10
 In main(): 10

Notes on proper usage

Pass by reference and call by reference are synonyms and are specific terms of art that indicate direct syntactical support in the language. Referring to the C mechanism used in the example above - passing a pointer to a variable in order to access the variable within the function - as "pass by reference" is technically incorrect. This is because within the function the language's syntax requires the dereferencing operator to be applied to the pointer, whereas true pass by reference, such as supported by Pascal (parameters declared with var) and C++ (parameters declared with &), does not have that requirement. Better and more correct is to refer to the C mechanism as "passing a reference".




Pass values using function parameters
The first is to pass data into the function using input parameters, as we looked at a few sessions back. Our program would look something like this:-
main()
{                                 |
  float f,res;                    | this is the scope of the f variable
  scanf("%f",&f);                 |
  res = one_over(f);              |
  printf(" res is %3.2f", res );  |
}
 
float one_over(float amt)
{
  float j;                 |
  if (amt==0) amt==1;      | this is the scope of the j variable
  j = 1 / amt;             | and the amt parameter variable
  return j;                |
}
We can see that we are passing the i variable into the one_over function. This gets copied into the amt local variable inside the function. This can then be changed if necessary (as it is here to ensure that we never divide by zero, although this is not a very good solution to the problem!).
The  result is then returned from the function (of type float as specified at the start of the function's definition line and prototype line), which has been calculated to be one divided by the original value.
Control is passed back to the original program, where one_over(f) is replaced with the return value - e.g. if f contained 2 then the value returned would be 1/2 (i.e. 1 divided by 2) - i.e. 0.5, so one_over(f) is replaced with 0.5, and the line in main() becomes res = 0.5. So res gets filled with the value 0.5 in this example.
Pass values using global variables
Another method, which is generally frowned upon by many, is to use variables that are available to every function in your program. These are called global variables.
To declare a global variable and make it available to all functions, just to the definition out of a specific function, and put it towards the top of your program - just above the main() function should be fine.  This implies that the scope of the variable has changed to be outside all functions, and therefore available to all functions. Our program can now look like this:-
float f,res;
 
main()                                              |
{                                                   |
  scanf("%f",&f);                                   |
  one_over;                                         | this is the scope 
  printf(" res is %3.2f", res );                    | of the res and f variables
}                                                   |
                                                    |
void one_over;                                      |
{                                                   |
  float amt;               |                        |
  amt = f;                 | this is the scope      |
  if (amt==0) amt==1;      | of the amt variable    |
  res = 1 / amt;           |                        |
}                                                   |
In this case, we have placed both the input (variable f) and output (variable res) as global variables. By doing so, we must always make sure we set variable f before we call the one_over function, as it is now providing the input.  We must also make sure that the variables res is set before the function ends, as this is now providing the output.
It would be possible to provide input as shown in the previous section, by passing a parameter, and providing the ouput as the res variable, and then we could keep the res variable local to the main() function.  This would mean that we could re-use the one_over function in different functions without the fear of overwriting the result.
We still run the risk of losing our input, if the one_over function is used in several different places - we risk mixing the inputs and outputs up of if we use it several different times. This is the advantage of keeping variables local, and passing parameters - this keeps the risk of overwriting something unintentionally to a minimum, and is the reason why you should not use global variables unless really necessary.
A typical example of where it would be okay to use a global variable might be a variable that is truly only ever used for one purpose throughout a program - for example score or high_score in a game, or userid in a password-protected application.



MORE EXAMPLES:

Pointer

Passing by pointer is where you pass a function a pointer to the object you want worked with. You are not actually changing the object itself, just the local or temporary copy that you have made with the pointer.

This code is wrong. Both output 10 and I can not for the life of me figure out why that is. Perhaps I am using pointers wrong.

Code:


#include <iostream>
 
int foo(int *bar)
{
    *bar = (*bar + *bar);
     
    return(*bar);
}
 
int main()
{
    int baz = 5;
    int *pbaz = &baz;
 
    std::cout << foo(pbaz); // Should equal 10
    std::cout << "\n" << baz; // Should equal 5
 
    std::cin.get();
    return(0);
}


Reference

Passing by reference means that you don't pass the value of an object, you are passing the object itself. There are no copies made, only the original object is what is worked with.

Code:
 
 
#include <iostream>
 
int foo(int &bar)
{
    bar = (bar + bar);
     
    return(bar);
}
 
int main()
{
    int baz = 5;
 
    std::cout << foo(baz); // Should equal 10
    std::cout << "\n" << baz; // Should equal 10
 
    std::cin.get();
    return(0);
}
 
 
 
 
Value

Passing by value means that you are taking a copy of what has been passed to the function, work with it in the function, but do not modify the original value.

Code:
 
 
#include <iostream>
 
int foo(int bar)
{
    bar = (bar + bar);
     
    return(bar);
}
 
int main()
{
    int baz = 5;
 
    std::cout << foo(baz); // Should equal 10
    std::cout << "\n" << baz; // Should equal 5
 
    std::cin.get();
    return(0);
}
 
 


References:

http://www.simonhuggins.com/courses/cbasics/course_notes/session19.htm

No comments:

Post a Comment