CSCE 2004 - Laboratory Assignment 12

    The objective of this lab is to give students more practice with object oriented programming. We will start by compiling and testing the "SafeArray" class. Then we will extend this class to add several useful methods. Finally, we will modify the SafeArray class so it can handle variable sized arrays instead of fixed size arrays. This lab has the following steps.

  1. Compiling the SafeArray Class
  2. In this section, we will be creating a "SafeArray" class. This data structure allows the user to store 20 float values in an array. It has several methods to input/output the data and other methods to modify/manipulate the data. Because it provides array bounds checking before accessing the array elements, it is a "safe" array implementation. The SafeArray class has the following methods:

    Step 1: Copy and paste the class interface below into a file called "safe_array.h". By convention, all C++ class interface files are stored in files with names ending with a ".h". Notice that this class has one private variable that is an array of 20 floats, and several public methods that use this array.

    #include <string>
    #include <cstdlib>
    #include <fstream>
    #include <iostream>
    using namespace std;
    const int SIZE = 20;
    
    class SafeArray
    {
    public:
       SafeArray();
       SafeArray(const SafeArray & array);
       ~SafeArray();
    
       bool GetElement(const int i, float & Value) const;
       bool SetElement(const int i, float Value);
       void ReadArray(const string Filename);
       void WriteArray(const string Filename) const;
       void Sort();
       void Print() const;
    
    private:
       float Array[SIZE];
    };
    

    Step 2: Copy and paste the class implementation below into a file called "safe_array.cpp". By convention, all C++ class interface files are stored in files with names ending with a ".cpp". Notice that this code includes the class interface file "safe_array.h", and all method names start with "SafeArray::" to indicate that they are part of the SafeArray class.

    #include "safe_array.h"
    
    SafeArray::SafeArray()
    {
       for (int i = 0; i < SIZE; i++)
       {
          Array[i] = 0.0;
       }
    }
    
    SafeArray::SafeArray(const SafeArray & array)
    {
       for (int i = 0; i < SIZE; i++)
          Array[i] = array.Array[i];
    }
    
    SafeArray::~SafeArray()
    {
    }
    
    bool SafeArray::GetElement(const int i, float & Value) const
    {
       bool Success;
       if (i < SIZE && i >= 0)
       {
          Success = true;
          Value = Array[i];
       }
       else
       {
          Success = false;
          cerr << "Array index " << i << " out of bounds!!" << endl;
       }
       return Success;
    }
    
    bool SafeArray::SetElement(const int i, float Value)
    {
       bool Success;
       if (i < SIZE && i >= 0)
       {
          Success = true;
          Array[i] = Value;
       }
       else
       {
          Success = false;
          cerr << "Array index " << i << " out of bounds!!" << endl;
       }
       return Success;
    }
    
    void SafeArray::ReadArray(const string Filename)
    {
       ifstream infile;
       infile.open(Filename.c_str());
       if (infile.fail())
       {
          cerr << "Error opening file: " << Filename << endl;
          exit(1);
       }
    
       int i = 0;
       while ((i < SIZE) && (infile >> Array[i]))
          i++;
       infile.close();
    }
    
    void SafeArray::WriteArray(const string Filename) const
    {
       ofstream outfile;
       outfile.open(Filename.c_str());
       if (outfile.fail())
       {
          cerr << "Error opening file: " << Filename << endl;
          exit(1);
       }
    
       for (int i = 0; i < SIZE; i++)
          outfile << Array[i] << endl;
       outfile.close();
    }
    
    void SafeArray::Sort()
    {
       float temp = 0.0;
       for (int i = 0; i < SIZE; i++)
       {
          for (int j = i + 1; j < SIZE; j++)
          {
    	 if (Array[j] < Array[i])
    	 {
    	    temp = Array[i];
    	    Array[i] = Array[j];
    	    Array[j] = temp;
    	 }
          }
       }
    }
    
    void SafeArray::Print() const
    {
       for (int i = 0; i < SIZE; i++)
          cout << "Array[" << i << "] = " << Array[i] << endl;
    }
    

    Step 3: Copy and paste the code below into a file called "main.cpp". Notice that this file is including "safe_array.h". This means that we can use the public methods of the SafeArray class in our main program. We are NOT allowed to access the private variables.

    #include "safe_array.h"
    
    int main()
    {
       // TO BE ADDED
    }
    

    Step 4: To compile the SafeArray class we are going to compile safe_array.cpp and main.cpp separately, and then combine the results to create an executable file. Because this is a multi-step process, we are going to create a makefile to save us typing. Create a file called "makefile" and copy/paste the following into the file. Make sure that there is a TAB character in front of the g++ commands and NOT spaces.

    main.exe: main.o safe_array.o
    	g++ -o main.exe main.o safe_array.o
    main.o: main.cpp safe_array.h
    	g++ -c main.cpp
    safe_array.o: safe_array.cpp safe_array.h
    	g++ -c safe_array.cpp
    

    Step 5: Now type in the command "make". You should see a sequence of three g++ commands that compile the code above to create main.exe. Now type "make" again to see what happens. The reason makefiles are so powerful is because they look at the time stamps of the input/output files to decide which commands to execute. This way, the make command only has to recompile the source files that have been modified and not every file. This is a huge time savings for large software projects.

    Run the command "ls -l" and copy and paste the output below.

  3. Testing the SafeArray Class
  4. As you noticed above, the main.cpp program is empty. Your task in this section is to write some code to test each of the methods in the SafeArray class. As always, we will do this in an incremental manner.

    Step 1: Add code to declare an object that is an instance of the SafeArray class. Then, add a method call to print the contents of this object to the screen. Compile your program by typing "make". Notice that main.cpp was compiled, but not safe_array.cpp.

    Run the program "./main.exe" and copy and paste the output below.

    Step 2: Add some more code to call the "SetElement" and "GetElement" methods several times each. The whole point of this class is to be a "safe" array implementation, so make sure you include calls to verify this is working as intended. Call the print method after all of your GetElement/SetElement calls to show what the array contains. Recompile using "make" as needed until the program is running correctly.

    Copy and paste your main.cpp program below.

    Run the program "./main.exe" and copy and paste the output below.

    Step 3: Use nano to create an ascii file called "input.txt" that contains 20 float values separated by spaces or newlines. Now modify your main program to call "ReadArray" to read this data file into the SafeArray object BEFORE the GetElement/SetElement calls. Recompile using "make" and run the program. Now move the ReadArray call AFTER the GetElement/SetElement calls. When you recompile and run, you should see a big difference from the previous version of main.

    Run the program "./main.exe" and copy and paste the output below.

    Step 4: The only methods you have not tested are "Sort" and "WriteArray". Add some more code to main.cpp to call these methods, and use the print method to see the results. Experiment a little to see what happens when you put these method calls in different places in the program. When you are finished, compile using "make" and run the program a final time.

    Copy and paste your final main.cpp program below.

    Run the program "./main.exe" and copy and paste the output below.

  5. Extending the SafeArray Class
  6. Now that you have compiled and tested the SafeArray class, you can see that the list of methods for this class is not very extensive. The goal of this section is to add several methods to the SafeArray class. This will require changes to safe_array.h (to define new methods), safe_array.cpp (to implement new methods), and main.cpp (to test new methods). We will add and test new methods one at a time.

    Step 1: Edit safe_array.h to add a new public method called "GetMinimum" that has no parameters and returns the float value which is the smallest value in the array. Now edit safe_array.cpp and type in the implementation of this method. This will require a loop over the 20 data values. Finally, edit "main.cpp" to call your "GetMinimum" method and print out the results. To recompile, type "make". Notice that this time both of the cpp files were compiled.

    Copy and paste your implementation of GetMinimum below.

    Step 2: Edit safe_array.h to add a new public method called "GetMaximum" that has no parameters and returns the float value which is the largest value in the array. Now edit safe_array.cpp and type in the implementation of this method. This should look very similar to GetMinimum. Finally, edit "main.cpp" to call your "GetMaximum" method and print out the results. To recompile, type "make".

    Copy and paste your implementation of GetMaximum below.

    Step 3: Edit safe_array.h to add a new public method called "GetAverage" that has no parameters and returns the float value which is the average value in the array. Now edit safe_array.cpp and type in the implementation of this method. This should look very similar to your other methods. Finally, edit "main.cpp" to call your "GetAverage" method and print out the results. To recompile, type "make".

    Copy and paste your implementation of GetAverage below.

    Step 4: You may have gotten tired of using arrays of just 20 floats by now. It is trivial to change this size to 100 by changing the constant SIZE, but this would not be very useful if we have some data files with 10 values and other data files with 50 values. What we really want is a SafeArray that can adapt to the number of data values that are in the input file.

    To do this, you must add a new private variable called "Size" to the SafeArray class and set this value to be equal to SIZE in the constructor function.

    Then, you must modify the ReadArray method to read data from the file until SIZE elements are read or end of file is reached. The actual number of values read must then be saved in "Size".

    Finally, you must change all of the other methods to change all instances of "SIZE" into "Size". This way, they will loop over 10 elements if the file had 10 values, and loop over 50 elements if the file had 50 elements.

    To test your changes above, delete 5 lines from the "input.txt" file and run your program to see what it does. You should see that only 15 values are displayed when you print out the array contents. Congratulations! Your SafeArray class is looking great.

    Copy and paste your implementation of ReadArray below.

    Run the program "./main.exe" and copy and paste the output below.

  7. Submit Work
  8. This lab assignment will be submitted electronically to the TAs once you fill in the fields below and click on the "submit" button. You do NOT need to print a copy of this document to hand in.

    Your UAID number:
    Your website PASSWORD: