Activity 10-2 - Arrays in Functions



You can use both the array index variables and the entire array itself as arguments to functions.  The following is perfectly valid:

double x[7] = {0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5};
double y[7];
int i;

for (i = 0; i<7; ++i)
        y[i] = sin(x[i]);

Here we send the value of x[i] (as one single value) to the sine function.  The function's parameter, in this case, is a call-by-value parameter.  When you deal with a single variable from the array, every thing is been seen as a single variable.  Thus, if one wants to update a value for the 5th element of an array in a different function, he/she has to use the call_by_reference.  Here is an example:

// P10_2.cpp - An array element as an argument to a function
#include <iostream>
using namespace std;

void get_grade(int& grade);
// Obtains a grade from the user and stores it in parameter, grade.

int main(void)
{
        int grades[5];
        int i;

        cout << "Enter 5 grades \n";
        for (i = 0; i<5; ++i)  // read, store values one-by-one
                get_grade(grades[i]);

        for (i = 0; i<5; ++i) // Displays the array
                cout << "grade[" << i << "] = " <<  grades[i] << endl;

        return 0;
}

void get_grade(int& grade)
{
        cout << "Input a grade between 0 and 100: ";
        cin >> grade;
}

Here, we update the elements of array grade, one-by_one. Thus, we have used a call-by-reference mechanism to update the values.  Note that there is a major difference between the grade in the function call and the one in the function definition.  In the statement:
 get_grade(grades[i]);

grades is the arrays grades[] and we are referring to its ith element, while in statement:
void get_grade(int& grade)

grade is a single integer.

We could use the entire array as an argument too. Here is the modified version of the above program.

// P10_2a.cpp - The entire array as an argument to a function
#include <iostream>
using namespace std;

void get_grade(int grade[]);

int main(void)
{
        int grades[5];
        int i;

        cout << "Enter 5 grades \n";

        get_grade(grades); // can read, modify all elements

        for (i = 0; i<5; ++i) // Displays the array
                cout << "grade[" << i << "] = " <<  grades[i] << endl;

        return 0;
}

void get_grade(int grade[])
{
        for (int i = 0; i<5; ++i)
        {
               cout << "Input a grade between 0 and 100: ";
               cin >> grade;
         }
}

Note that we no longer need to pass the array as call-by-reference, no need for &, because once you call the function as:
        get_grade(grades); // can read, modify all elements

You have passed the address of the first element of the array, i.e., the address of grade[0],  to the function get_grade.  The declaration of the array in the get_grade definition is:

void get_grade(int grade[])

which means, an array of some size that starts from the address that was passed to it from the function call, i.e. an array of some consecutive addresses starting from the address of grad [0].  Thus, if in function get_grade you use an array of 5 elements, the memory address of that array will be the same as the array grades that was defined in the main.

Using const with an Array Parameter
If you place the reserved word const in front of an array parameter, the function cannot change the value of any of the elements of the array. An attempt to do so, will result in a syntax error.  This is a good idea if you are writing a function that will be used by other programmers and you want to make it clear to them that your function will not make any changes to the array that is passed to it. On the other hand, sometimes we want to make chnages in the array.  For example, in the above program if we had used:
void get_grade(const int grade[])

Then, we would be unable to update the elements of the array.

Partially Filled Arrays
Sometimes we don't know in advance how many values we will store in an array. In such a case, we declare the array to be of a size large enough for storing the maximum number of values we may have. Then, as we fill the array, we count the number of elements that get filled and use that count as the used size of the array.  Soon you will see an example of a partially filled array. First, let's describe a program that requires using this example.

Suppose we want to write a program to add very large integers. Our C++ compiler's integer data type is stored in 4 bytes. This means that the largest integer we
can store in an integer variable is approximately 2 billion. If we need larger integers, we will have to develop a new way of storing them.  One way to store a large integer is to store the digits of the integer in a character array. Let's say that we will never need integers with more than 20 digits. Then we can declare a character array of size 20 and be sure that any of our large integers will fit into it. As we fill the array with digit characters, we will count the digits so that we know how many elements are currently filled. Here is the example:

// P10_2b.cpp - An example for partially filled arrays
// Saving very large integers as array of characters

#include <iostream>
#include <ctype>
using namespace std;

const int MAXSIZE = 20;

int main(void)
{
        char digit_array[MAXSIZE], digit;
        int size, i;

        size = 0;
        cout << "Enter an integer with no more than 20 digits: ";
        do {
                cin.get(digit);
                if (isdigit(digit))
                {
                        digit_array[size] = digit;
                        ++size;
                }
        } while (size < 20 && isdigit(digit));

        cout << "The integer you entered is: ";
        for (i = 0; i<size; ++i)
                cout << digit_array[i];
        cout << endl;
        return 0;
}

Partially Filled Arrays as Function Argument
Sometimes you have a partially filled array and you want to pass that to a function as an argument.  In such a case, it is best to pass the used size of the array as an argument as well.  For example, in the above program suppose we want to use a function that does the reading and another one that does the writing.  So we will have the read_array and write_array functions with two arguments.  Here is the modified version of the program.

// P10_2c.cpp - An example for partially filled arrays
// Saving very large integers as array of characters
#include <iostream>
#include <ctype>
using namespace std;

const int MAXSIZE = 20;
void read_array(char d_array[], int& size); // array will be modified
void write_array(const char d_array[], int size); // array will not be modified

int main(void)
{
        char digit_array[MAXSIZE];
        int size, i;

        size = 0;
        cout << "Enter an integer with no more than 20 digits: ";
        read_array(digit_array, size);
        write_array(digit_array, size);

        return 0;
}

void read_array(char d_array[], int& size)
{
       char digit;
       do {
                cin.get(digit);
                if (isdigit(digit))
                {
                        d_array[size] = digit;
                        ++size;
                }
        } while (size < 20 && isdigit(digit));
}

void write_array(const char d_array[], int size)
{
        cout << "The integers you entered are: ";
        for (int i = 0; i<size; ++i)
                cout << d_array[i];
        cout << endl;
}

Exercise 10.2
Write a program that asks users to input up to 20 integers, and then finds the maximum, minimum, average, and median of the numbers that were entered.

Median is the number that appears in the middle of the sorted list of numbers.  If the array has an odd number of elements, median is a single number in the middle of the list (array).  If the array has an even number of elements, then median is the average of the two numbers in the middle.

Example:
Odd number of elements:   1 4 6 3 8, first sort the numbers: 1 3 4 6 8, then find the median, i.e, 4.
Even number of elements:   1 4 8 3, first sort the numbers:  1 3 4 8, then find the median as the average of 3 and 4, i.e., 3.5

To find the smallest element in an array, you only need to find the index of the smallest number.  You can use the following function to do this.  This function is also used in the sort_array function.

int index_of_smallest(const int a[], int start_index, int user_size)
{
      int min = a[start_index], index_of_min = start_index;
     for(int i = start_index+1; i < used_size; i++)
          if(a[i] < min )
          {
                min = a[i];
                index_of_min = i;
           }
           return index_of_min;
}

To sort an array that has used_size elements, use the following function:

void sort_array(int a[], int used_size)
{
      int index_of_next_smallest;
      int temp;

      for(int i = 0; i < used_size-1; i++)
      {
              index_of_next_smallest = index_of_smallest(a, index, used_size);
              // swap two elements
              temp = a[i];
              a[i] = a[index_of_next_smallest];
              a[index_of_next_smallest] = a[i];
       }
}

Note that you can write three more functions; 1) one similar to the one that finds the index of smallest number for finding the index of the largest number, 2) one that computes the average and returns it to the main, 3) and the last one that takes the sorted array and will return the median.