Lab 12 -- One-dimensional Arrays

Click Here to CREATE ANSWER SHEET for Lab 12

Objectives:

Sections:

  1. Background
  2. Introduction to One-Dimensional Arrays
  3. Declaring One-Dimensional Arrays
  4. Accessing an Array Element
  5. A One-dimensional Array as a Parameter
  6. Searching an Array
  7. The Linear Search
  8. The Binary Search
Background
Most of the data encountered in everyday life occurs in groups rather than in individual pieces. Data items tend to be collected into conceptual units with names assigned to them.

In this lab we will introduce the array, a homogeneous data construct used to represent a group of data where each element of the group is of the same data type. This data construct might be used to store many items of the same type as a conceptual unit. For example, all of the scores made on a test by students in a biology class might be stored in an array, or the names of students in a biology class might be stored in an array.

(In another lab we will learn about two other C++ composite data constructs, the struct and the class, that can be used to represent heterogeneous groups of data. These two data constructs are used to store many data items of different types as a conceptual unit. For example, the struct or class could be used to store information about a student -- like name, classification, etc. . )

Introduction
To understand what an array is, we first review what a variable is. A variable is a symbolic name for a specific location in main memory. For example, the statements:


       int x;
          .
          .
       x = 25;

instruct the computer to set aside a memory location that will hold an integer, giving the memory location the symbolic name x. The second statement instructs the computer to store the integer 25 in the memory location with the symbolic name x.

How can we store twenty integers in memory? We could dream up twenty different symbolic names, such as x1, x2, x3, ..., x20, for twenty places in memory. Obviously, this is not convenient. C++ has a data type called an array that addresses this particular problem.

An array, then is a group of locations in memory such that a) the locations are usually consecutive, b) all of these locations will contain the same type of data, and c) all of these locations are referenced by the same symbolic name.

Arrays are used anytime we wish to store and manipulate more than a few pieces of data of the same type. Consider the following examples:

  1. Suppose that we wish to compute the average pay for 30 people. We do not require an array for this application, since we do not need to remember the data for all 30 people. In this problem we input data for one person and add it to an accumulator. We can use the same variable for the next person, since we no longer need to remember data for the previous person.
  2. Suppose we wish to print out 30 scores in reverse order. We need an array for this application because we must remember all 30 numbers in order to print them out in reverse.
Declaring One-Dimensional Arrays
Suppose we need an array to store 30 integer scores. We might accomplish this using the following C++ code:

        const int MAX_SCORES = 30;
        int scores[MAX_SCORES];

Note the use of the constant MAX_SCORES for the upper limit on the size of the array. Using a const value to denote the size of the array is not required but is good programming practice. This code causes 30 locations in memory to be set aside under the name scores where each location (aka element) is of the data type int. This array, scores, can hold up to 30 integer values. (We sometimes use the term extent to refer to how many elements an array can store. In this example, because MAX_SCORES is set to 30, the extent of the scores array is 30.) It is said to be one-dimensional because it uses only one set of square brackets [ ] in its declaration.


Exercise 1:
On the answer sheet, declare a one-dimensional array that could be used to hold data for the salaries (float type) of 100 employees.

Accessing an Array Element
In order to store information in an array, one must:

  1. Specify the name of the array and
  2. Specify exactly which location in the array is to be used to store the information.

We specify locations in the array by using an index (aka a subscript). For example, reconsider the array scores defined above. The C++ statement scores[i]=20; means: look at the location designated by i in the array list and store the value 20 in this position. The index can be a constant, variable, or expression as shown below:


      scores[5] = 100;         //index = 5
      scores[x] = 80;          //index = the value of the variable x
      scores[3*x] = 75;        //index = three times x

To determine valid values for the index, reconsider the definition of the array:

      int scores[MAX_SCORES];

The upper limit of the index is calculated from the value in brackets, namely MAX_SCORES - 1. In C++, the lower limit is always 0. Thus the index may vary from 0 to MAX_SCORES - 1. Thus the first memory location assigned to scores is designated by the first index value 0, the second by index value 1, and so on, up to the last one which is designated by the index value MAX_SCORES - 1. If, instead, scores were declared as follows:

      int scores[MAX_SCORES + 1];

then we could access scores[0], scores[1],..., scores[MAX_SCORES].

Usually a loop of some kind is used when one is working with an array. The following code could be used to read in an array of values from the keyboard.


      //read the number of scores
      cout << "How many scores?\n";
      cin >> howMany;

      //now read the scores
      for (int i = 0; i < howMany; i++)
      {
           cout << "Input scores[" << i << "]: ";
           cin >> scores[i];
      }


Exercise 2:
Fill in the blanks below to print the entire scores array to the screen. Place your answers on the answer sheet.


1     //print the scores
2     for (int i = ____; i _______________; i++)
3     {
4           cout <<"The value of score[" << i << "] is ";
5           cout << ___________________ << endl;
6     }
A One-dimensional Array as a Parameter
A function could also be used to read an array. For example, the following function might be used to read an array of values from an input file stream. The array's actual size as well as all of the elements in the array are read from the file. Note the "actual" size of the array may not be the same as the MAX_SCORES used to declare the array. We think of MAX_SCORES as the biggest size that we would ever need for this array. We think of the "actual" size as how much of the array is being used on one particular run of the program.


      void ReadInScores (ifstream& ins, int scores[], int& howMany)
      {
           //read the number of scores
           ins >> howMany;

           //now read the scores
           for (int i = 0; i < howMany; i++)
           {
                ins >> scores[i];
           }

      }

Note: When an array is passed as an argument, we do not have to indicate the size of the array. Notice the empty brackets [] in the parameter list. These empty brackets [] tell the compiler that scores is an array of int rather than just a simple int.

WARNING 1: All arrays in C++ are pass-by-reference when used as function parameters. This means that when an array appears in the argument list of an activation statement (aka calling statement), the address of the array is sent to the function, not the contents of the array! Therefore, the array in the parameter list will be an alias (will refer to) to the same array as the argument.

WARNING 2: Use the reserve word const in the parameter list if an array is used and the contents of the array should NOT be altered. As an example, consider the following function header:

     void PrintScores(const int scores[], int howMany)

The values in the array scores can not be change in the PrintScores() function because we have used const in the parameter list. Therefore, we can protect the contents of the array by using const.

In a main program, we might have the following statements to declare an array and to use the functions above to read values into the array and print them.

    const int MAX_SCORES = 30;   //the array has at most 30 entries
    int scores [MAX_SCORES];     //an array of test scores with 30 entries
    int howMany;                 //the actual size of the array
    ifstream ins;                //the input file stream containing scores

    //open the input file
    ins.open("scores.dat");

    //call the function to read the scores
    ReadInScores(ins, scores, howMany);


    //call the function to print the scores
    PrintScores(scores, howMany);

Notice that when an array appears as an argument in a call statement, only the name of the array is needed. It would be an error to place the brackets after the array name in the argument list.


Exercise 3:
Copy the file cla12a.cpp to your account. Also copy the file scores.dat to your account. Notice that the program contains a function ReadInScores that reads from the file scores.dat. The program contains an activation statement for PrintScores. You should add a function definition and a function prototype for PrintScores . The function should print the scores in the array scores. Compile and run the program. Make sure the revised program works before continuing to the next exercise.


Exercise 4:
Notice that the program from Exercise 3 contains a function to determine the average of the array scores. Add an activation statement to determine the average of the array scores and add a statement to print the average.


Exercise 5:
Add and invoke a function to your program called AboveAverage(). This function should receive the array of scores, the number of scores, and the average score. The function should print all scores that are greater than the average. Compile and run your program.


Searching an Array
One of the most common list operations is searching for an item in the list. In this section, we'll consider searching an array for a value, determining whether a value is in the array, and, if so, determining the value's index. There are two commonly used search techniques, one that can be done on any list and one that requires the list to be sorted.

Linear search
Often an array of elements has not been sorted in any particular order. When this is the case and we wish to determine the location of a particular value in an array, we must use a special search called the linear search to solve this problem.

With a linear search technique, you look at every element in the array, one-at-a-time beginning at the first. When the value is found, quit immediately. If you get through the entire array without quitting, then the search is unsuccessful -- the value is not in the array.

The method LinearSearch() returns the index of the searched value in the array. If the value is not in the array, LinearSearch() returns -1.

int LinearSearch (int a[], int aSize, int toFind) 
{ 
     // Look through all items, starting at the front. 
     for (int i = 0; i < aSize; i++)     
         if (a[i] == toFind)            
             return i; 
  
     // You've gone through the whole list without success.  
     return -1; 
}

Here is an array, which is a list of integer values.

  int list[12] = {3,15,2,8,7,1,14,38,10,-2,61,5};

Suppose we wish to search this one-dimensional array for the value 10. Below we illustrate the call to the function above that would accomplish this:

index = LinearSearch(list,12,10)
The illustration below, shows what the function would cause to happen.

Image: Linear search (item belongs to list)

After control returns to the activating function, index will contain 8.

The second illustration below is for the call index = LinearSearch(list,12,25). After control returns to the activating function, index will contain -1 meaning that the function did not find 25 in the array. The search goes all the way to the end of the array, since 25 is not in the list.

Image: linear search for an item not in the list

Note: The search can be shortened if you know something about the array. If the array is ordered, then you can quit as soon as you reach a value that is bigger than the one being searched.



Exercise 6:
On the answer sheet, place the value of index after each of the following activation statements:

1.     index = LinearSearch (list, 12, 3);
2.     index = LinearSearch (list, 12, 21);

Exercise 7:
Add the LinearSearch() function to your program, cla12a.cpp. In the main program, add a loop to enter values and search for them in the scores array using the function. In the loop, a value should be input. Then the function should be used to search for the value. Finally, the index where the value was found should be printed (or a message saying the value was not found). The loop should terminate when the sentinel data -99 is read. Submit a script log containing a printout of cla12a.cpp, a compile, and a run using the data values: 55 10 59 70 -99 Something like the following UNIX commands will let you submit what is required:
            $ script lab12ex7.log
            $ pr -n -t -e4 cla12a.cpp
            $ c++ cla12a.cpp -o cla12a
            $ cla12a
            55 10 59 70 -99
            $ exit
            $ handin "lab12log" lab12ex7.log
(Be sure to exit the script session before trying to submit the log!)

The Binary Search
A binary search can be used on an array that has been sorted into ascending or descending order. The algorithm for a binary search is as follows.

The C++ function below performs a binary search on an integer array a with size aSize. The function searches for the value toFind and returns the index of its location in the array or the value -1 if the value was not found.
int BinarySearch(int a[], int aSize, int toFind)
{
    int start = 0;                         //the search starts with index 0
    int last = aSize -1;                   //last is the last array index
 
    while (start <= last)                  //while there is still a place to look.      
    {
         int middle = (start + last) / 2;  //Look here first
         if (toFind == a[middle])          //Found item. Quit. 
               return middle;
         if (toFind > a[middle])           //Look in the last half
               start = middle + 1;
         else                              //OR look in the first half
               last =  middle - 1;
    }
    //the element wasn't found
    return -1;
}

Consider these declarations.

  int list[12] = {-2,1,2,3,5,7,8,10,14,15,38,61}; 
  int val;                     // An item to search for in the list 
  int index;                   // Index of val in the list  

  // .. assign something to val   
  index = BinarySearch(list, 12, val);

The illustration uses a sorted version of the list of the last example to trace this call: BinarySearch(list,12,10) :

The activation statement: BinarySearch(list,12,10) returns 7

Image: successful 
binary search

The final illustration is of an unsuccessful search: BinarySearch(list,12,25). On the final call, start is 10 and last is 9.

Image: unsuccessful 
binary search

Why use a binary search when a linear search is easier to code? The answer lies in the efficiency of the search. With a linear search, if you double the size of a list, you could potentially take twice as much time to find an item. With a binary search, doubling the size of the list merely adds one more item to look at. Each time you look with a binary search, you eliminate half of the remaining list items as possible matches.

Exercise 8:
Trace the calls to BinarySearch() below and determine the index of each "guess" examined by this function. Also determine the value of index after the function returns. Place your answers on the answer sheet.

1.      index = BinarySearch (list, 12, -2);
2.      index = BinarySearch (list, 12, 100);

For example, if you wished to trace the call BinarySearch(list, 12, 10), you might place the following on the answer sheet:
    Guess 1: middle = 5
    Guess 2: middle = 8
    Guess 3: middle = 6
    Guess 4: middle = 7 
    Function returns 7

Exercise 9:

From the PC you are working on, you must also submit the answer sheet (AnswerSheet12.pdf) using the following directions:


Congratulations! You have finished Lab 12.



Once you are done, you will need to log off ranger. Enter   $ exit   to exit the (sakura) terminal window. Depending on how you logged in to ranger you will need to enter $ exit one or more times to get completely logged off the system.