Difference between revisions of "ES101 - Lesson 8 : Functions with Pass-By-Reference"

From Embedded Systems Learning Academy
Jump to: navigation, search
(Objective)
(Objective)
Line 7: Line 7:
 
*  '''VIDEO : [http://www.youtube.com/watch?v=kQPN5dA5t8A Pointers in C/C++]'''
 
*  '''VIDEO : [http://www.youtube.com/watch?v=kQPN5dA5t8A Pointers in C/C++]'''
 
*  '''VIDEO : [http://www.youtube.com/watch?v=OlXEQaL8JT4 Pointer use in functions in C/C++]'''
 
*  '''VIDEO : [http://www.youtube.com/watch?v=OlXEQaL8JT4 Pointer use in functions in C/C++]'''
 +
*  '''VIDEO : [http://www.youtube.com/watch?v=GyA2b7PHUlU Pointer to arrays passed to functions in C/C++]'''
  
 
== Basics of Pointers ==
 
== Basics of Pointers ==

Revision as of 03:17, 29 March 2013

Objective

You will learn the basics of pointers, which are used in combination with the functions.

When functions pass a parameter by value, they provide copies of their variables that get duplicated as parameters of a function. By definition, the original variable(s) provided remain unaffected if their copies are modified. The alternate to "pass-by-value" is "pass-by-reference" which will actually provide original variable's address so that the function may alter the values. More specifically, instead of a function taking a variable as parameter, the function will take a pointer to the variable as parameter.

You can view the following screencast to review this lesson, but should read through this material regardless :

Basics of Pointers

So far, pass-by-value is what you've used when you designed your functions to take inputs as parameters. Pass-by-reference passes a variable's memory address instead of the variable's value; therefore, you can change the data at that memory address hence changing the input value. Let's start with the basics of a pointer:

void main()
{
    int my_int_one = 0;
    int my_int_two = 0;

    // A pointer is declared by using the *
    int *my_int_ptr;

    // Pointer can only be set equal to an address, so :
    // Set it equal to address of my_int_one by using & (address) operator
    my_int_ptr = &my_int_one;

    // * means to dereference
    // Modify the memory pointed by my_int_ptr which will write to address of my_int_one:
    *my_int_ptr = 1;

    // Without using my_int_one, we modified it to be the value of 1
    printf("my_int_one = %i\n", my_int_one);

    // Let's modify my_int_two indirectly:
    my_int_ptr = &my_int_two; // <-- Change pointer location
    *my_int_ptr = 2;          // <-- Change value at the pointed location

    // This will print 2:
    printf("my_int_two = %i\n", my_int_two);
}

Let's summarize important points:

  • A pointer is declared by using the * right before the variable name
  • A pointer can point to different memory locations by setting it to & (address) of another variable
  • A pointer's pointed value can be changed by dereferencing it.


Pass By Reference

Pass by reference provides a mean to provide input to functions by specifying a memory location, which allows the function to modify caller's variables. In other words, instead of just merely giving a value, you pass the pointer of variable(s), and the pointer points to the memory address where the data is stored. The values are then accessed by using the * operator inside the function, which is called the dereference operator. Students often get confused with & and * symbols. & refers to the memory address whereas as * refers to a value stored at this memory address.

// Declare foobar() that takes pointers of int and float
void foobar(int *intInput, float *fpInput);

int main(void)
{
   // We can no longer do this since we have to provide
   // addresses of some variable
   foobar(1, 1.2);        // ERROR!
   foobar(anInt, aFloat); // ERROR!

   // Pass variable addresses to foobar()
   int anInt = 1;
   float aFloat = 2.3;
   foobar(&anInt, &aFloat);

   // After function call to foobar(): anInt and aFloat are zero
   printf("Variables now: %i, %f\n", anInt, aFloat);
}

void foobar(int *intInput, float *fpInput)
{
   /*********
    * Two things to note :
    *   - intInput points to address of main()'s anInt
    *   - fpInput  points to address of main()'s aFloat
    *
    *  We can modify main()'s variables using these pointers 
    */
   printf("Input was: %i, %f\n", *intInput, *fpInput);

   // Modify the inputs:
   *intInput = 0;
   *fpInput  = 0;
}

Similar to how you provided address to scanf function, you must provide address of variables to foobar(), when calling the function otherwise a compiler error will be encountered as seen by first two calls to foobar() in the figure above. The third call to foobar() shows correct function call, which passes addresses of anInt and aFloat variables. The main() function called foobar() with values as 1 and 2.3, and, after foobar() returns, the values of the variables are set to 0 by foobar().

Passing Arrays to a Function

Passing arrays to a function is not much different than passing a pointer. This is because to pass an array to a function, you actually pass the address of its first element. Since the address of the first element is available, any element of the array can be accessed by offsetting its starting address. See the examples below for illustration.

float getSumOfFloatingPointArray(float *floatArray, int elements);

int main(void)
{
   float samples[4] = {1.1, 2.2, 3.3, 4.4};
   float sum = getSumOfFloatingPointArray(samples, 4);
   printf("Sum = %f\n", sum);
}

float getSumOfFloatingPointArray(float *floatArray, int elements)
{
   int i = 0;
   float sum = 0;
   for(i = 0; i < elements; i++)
   {
      // Use ordinary array index method to access/modify the array
      sum += floatArray[i];
   }

   return sum;
}

Notice that when main() calls the getName() and getSumOfFloatingPointArray() functions, it just passes the arrays without the & operator; this is because the array name itself is the address of the first element of the array.

When you pass an array to a function, the function needs to know the number of elements that belong to the array. Without this information, the function would not know the size of the array memory allocation. Once an array is passed to a function, the function can access it just like normal array indexed elements because the index acts like an offset of the base address of the array.

Assignment

Build Functions

Declare and define the following functions:

  1. getInt()
    • Takes no parameters, and returns an integer
    • Performs printf/scanf inside this function and return the number back
  2. getFloat()
    • Same as getInt(), but returns a scanned floating point number instead
  3. swap()
    • Returns nothing
    • Takes two integer pointers as parameters
    • Swaps the numbers at these pointers
  4. getAverage()
    • Takes a pointer to an array of floating point numbers
    • Takes the number of elements in the array as input
    • Computes the average of the array and returns it
    • No printf/scanf should take place inside this function.

Objectives

Use the sample code below to complete the objectives :

  1. Get two numbers using getInt()
    Swap them using swap(), and print them out.
  2. Declare an array of five floating point numbers
    Compute the average using getAverage() and print out the average.
int main(void)
{

    int my_int_one = getInt();
    int my_int_two = getInt();
    
    // TODO : Call your swap() function to swap values of my_int_one, and my_int_two
    //          Then print the values of my_int_one and my_int_two

    // TODO : Declare array of 5 floating-point numbers

    // TODO : Use a for loop to get input and store to the array elements :

    // TODO : Call getAverage function to get the average

    return 0;
}

Questions

Answer the following questions to complete the lab.

  1. Although pass-by-reference can be used to substitute all pass-by-value functions, why is pass-by-value be considered safer?
  2. When passing an integer array to a function, why do you also need to pass the number of elements in that array?