7.10. Case Study: Class GradeBook Using a Two-Dimensional Array

In Section 7.6, we presented class GradeBook (Figs. 7.167.17), which used a one-dimensional array to store student grades on a single exam. In most semesters, students take several exams. Professors are likely to want to analyze grades across the entire semester, both for a single student and for the class as a whole.

Storing Student Grades in a Two-Dimensional Array in Class GradeBook

Figures 7.237.24 contain a version of class GradeBook that uses a two-dimensional array grades to store the grades of a number of students on multiple exams. Each row of the array represents a single student's grades for the entire course, and each column represents all the grades the students earned for one particular exam. A client program, such as fig07_25.cpp, passes the array as an argument to the GradeBook constructor. In this example, we use a ten-by-three array containing ten students' grades on three exams.

Fig. 7.23. Definition of class GradeBook with a two-dimensional array to store grades.

 

 1   // Fig. 7.23: GradeBook.h
 2   // Definition of class GradeBook that uses a
 3   // two-dimensional array to store test grades.
 4   // Member functions are defined in GradeBook.cpp
 5   #include <string> // program uses C++ Standard Library string class
 6   using std::string;
 7
 8   // GradeBook class definition
 9   class GradeBook
10   {
11   public:
12      // constants
13      const static int students = 10; // number of students
14      const static int tests = 3; // number of tests
15
16      // constructor initializes course name and array of grades
17      GradeBook( string, const int [][ tests ] );
18
19      void setCourseName( string ); // function to set the course name
20      string getCourseName(); // function to retrieve the course name
21      void displayMessage(); // display a welcome message
22      void processGrades(); // perform various operations on the grade data
23      int getMinimum(); // find the minimum grade in the grade book
24      int getMaximum(); // find the maximum grade in the grade book
25      double getAverage( const int [], const int ); // get student's average
26      void outputBarChart(); // output bar chart of grade distribution
27      void outputGrades(); // output the contents of the grades array
28   private:
29      string courseName; // course name for this grade book
30      int grades[ students ][ tests ]; // two-dimensional array of grades
31   }; // end class GradeBook

					  


Fig. 7.24. GradeBook class member-function definitions manipulating a two-dimensional array of grades.

 

 1   // Fig. 7.24: GradeBook.cpp
 2   // Member-function definitions for class GradeBook that
 3   // uses a two-dimensional array to store grades.
 4   #include <iostream>
 5   using std::cout;
 6   using std::cin;
 7   using std::endl;
 8   using std::fixed;
 9
10   #include <iomanip> // parameterized stream manipulators
11   using std::setprecision; // sets numeric output precision
12   using std::setw; // sets field width
13
14   // include definition of class GradeBook from GradeBook.h
15   #include "GradeBook.h"
16
17   // two-argument constructor initializes courseName and grades array
18   GradeBook::GradeBook( string name, const int gradesArray[][ tests ] )
19   {
20      setCourseName( name ); // initialize courseName
21
22      // copy grades from gradeArray to grades                         
23      for ( int student = 0;  student < students; student++ )          
24                                                                       
25         for ( int test = 0;  test < tests; test++ )                   
26            grades[ student ][ test ] = gradesArray[ student ][ test ];
27   } // end two-argument GradeBook constructor
28
29   // function to set the course name
30   void GradeBook::setCourseName( string name )
31   {
32      courseName = name; // store the course name
33   } // end function setCourseName
34
35   // function to retrieve the course name
36   string GradeBook::getCourseName()
37   {
38      return courseName;
39   } // end function getCourseName
40
41   // display a welcome message to the GradeBook user
42   void GradeBook::displayMessage()
43   {
44      // this statement calls getCourseName to get the
45      // name of the course this GradeBook represents
46      cout << "Welcome to the grade book for\n" << getCourseName() << "!"
47         << endl;
48   } // end function displayMessage
49
50   // perform various operations on the data
51   void GradeBook::processGrades()
52   {
53      // output grades array
54      outputGrades();
55
56      // call functions getMinimum and getMaximum
57      cout << "\nLowest grade in the grade book is " << getMinimum()
58         << "\nHighest grade in the grade book is " << getMaximum() << endl;
59
60      // output grade distribution chart of all grades on all tests
61      outputBarChart();
62   } // end function processGrades
63
64   // find minimum grade in the entire gradebook
65   int GradeBook::getMinimum()
66   {
67      int lowGrade = 100;  // assume lowest grade is 100
68
69      // loop through rows of grades array                               
70      for ( int student = 0;  student < students; student++ )            
71      {                                                                  
72         // loop through columns of current row                          
73         for ( int test = 0;  test < tests; test++ )                     
74         {                                                               
75            // if current grade less than lowGrade, assign it to lowGrade
76            if ( grades[ student ][ test ] < lowGrade )                  
77               lowGrade = grades[ student ][ test ]; // new lowest grade 
78         } // end inner for                                              
79      } // end outer for                                                 
80
81      return lowGrade; // return lowest grade
82   } // end function getMinimum
83
84   // find maximum grade in the entire gradebook
85   int GradeBook::getMaximum()
86   {
87      int highGrade = 0;  // assume highest grade is 0
88
89      // loop through rows of grades array                                          
90      for ( int student = 0;  student < students; student++ )                       
91      {                                                                             
92         // loop through columns of current row                                     
93         for ( int test = 0;  test < tests; test++ )                                
94         {                                                                          
95            // if current grade greater than lowGrade, assign it to highGrade       
96            if ( grades[ student ][ test ] > highGrade )                            
97               highGrade = grades[ student ][ test ]; // new highest grade          
98         } // end inner for                                                         
99      } // end outer for                                                            
100
101      return highGrade; // return highest grade
102   } // end function getMaximum
103
104   // determine average grade for particular set of grades
105   double GradeBook::getAverage( const int setOfGrades[], const int grades )
106   {
107      int total = 0;  // initialize total
108
109      // sum grades in array
110      for ( int grade = 0;  grade < grades; grade++ )
111         total += setOfGrades[ grade ];
112
113      // return average of grades
114      return static_cast< double >( total ) / grades;
115   } // end function getAverage
116
117   // output bar chart displaying grade distribution
118   void GradeBook::outputBarChart()
119   {
120      cout << "\nOverall grade distribution:" << endl;
121
122      // stores frequency of grades in each range of 10 grades
123      const int frequencySize = 11;
124      int frequency[ frequencySize ] = {}; // initialize elements to 0
125
126      // for each grade, increment the appropriate frequency 
127      for ( int student = 0;  student < students; student++ )
128                                                             
129         for ( int test = 0; test < tests; test++ )          
130            ++frequency[ grades[ student ][ test ] / 10  ];  
131
132      // for each grade frequency, print bar in chart
133      for ( int count = 0;  count < frequencySize; count++ )
134      {
135         // output bar label ("0-9:", ..., "90-99:", "100:" )
136         if ( count == 0  )
137            cout << "  0-9: ";
138         else if ( count == 10  )
139            cout << "  100: ";
140         else
141            cout << count * 10  << "-" << ( count * 10  ) + 9  << ": ";
142
143         // print bar of asterisks
144         for ( int stars = 0;  stars < frequency[ count ]; stars++ )
145            cout << '*';
146
147         cout << endl; // start a new line of output
148      } // end outer for
149   } // end function outputBarChart
150
151   // output the contents of the grades array
152   void GradeBook::outputGrades()
153   {
154      cout << "\nThe grades are:\n\n";
155      cout << "            "; // align column heads
156
157      // create a column heading for each of the tests
158      for ( int test = 0;  test < tests; test++ )
159         cout << "Test " << test + 1  << "  ";
160
161      cout << "Average" << endl; // student average column heading
162
163      // create rows/columns of text representing array grades
164      for ( int student = 0;  student < students; student++ )
165      {
166         cout << "Student " << setw( 2  ) << student + 1;
167
168         // output student's grades
169         for ( int test = 0;  test < tests; test++ )
170            cout << setw( 8  ) << grades[ student ][ test ];
171
172         // call member function getAverage to calculate student's average;
173         // pass row of grades and the value of tests as the arguments
174         double average = getAverage( grades[ student ], tests );
175         cout << setw( 9 ) << setprecision( 2 ) << fixed << average << endl;
176      } // end outer for
177   } // end function outputGrades

					  


Five member functions (declared in lines 23–27 of Fig. 7.23) perform array manipulations to process the grades. Each of these member functions is similar to its counterpart in the earlier one-dimensional array version of class GradeBook (Figs. 7.167.17). Member function getMinimum (defined in lines 65–82 of Fig. 7.24) determines the lowest grade of any student for the semester. Member function getMaximum (defined in lines 85–102 of Fig. 7.24) determines the highest grade of any student for the semester. Member function getAverage (lines 105–115 of Fig. 7.24) determines a particular student's semester average. Member function outputBarChart (lines 118–149 of Fig. 7.24) outputs a bar chart of the distribution of all student grades for the semester. Member function outputGrades (lines 152–177 of Fig. 7.24) outputs the two-dimensional array in a tabular format, along with each student's semester average.

Member functions getMinimum, getMaximum, outputBarChart and outputGrades each loop through array grades by using nested for statements. For example, consider the nested for statement in member function getMinimum (lines 70–79). The outer for statement begins by setting student (i.e., the row subscript) to 0, so the elements of row 0 can be compared with variable lowGrade in the body of the inner for statement. The inner for statement loops through the grades of a particular row and compares each grade with lowGrade. If a grade is less than lowGrade, lowGrade is set to that grade. The outer for statement then increments the row subscript to 1. The elements of row 1 are compared with variable lowGrade. The outer for statement then increments the row subscript to 2, and the elements of row 2 are compared with variable lowGrade. This repeats until all rows of grades have been traversed. When execution of the nested statement is complete, lowGrade contains the smallest grade in the two-dimensional array. Member function getMaximum works similarly to member function getMinimum.

Member function outputBarChart in Fig. 7.24 is nearly identical to the one in Fig. 7.17. However, to output the overall grade distribution for a whole semester, the member function uses a nested for statement (lines 127–130) to create the one-dimensional array frequency based on all the grades in the two-dimensional array. The rest of the code in each of the two outputBarChart member functions that displays the chart is identical.

Member function outputGrades (lines 152–177) also uses nested for statements to output values of the array grades, in addition to each student's semester average. The output in Fig. 7.25 shows the result, which resembles the tabular format of a professor's physical grade book. Lines 158–159 print the column headings for each test. We use a counter-controlled for statement so that we can identify each test with a number. Similarly, the for statement in lines 164–176 first outputs a row label using a counter variable to identify each student (line 166). Although array indices start at 0, note that lines 159 and 166 output test + 1 and student + 1, respectively, to produce test and student numbers starting at 1 (see Fig. 7.25). The inner for statement in lines 169–170 uses the outer for statement's counter variable student to loop through a specific row of array grades and output each student's test grade. Finally, line 174 obtains each student's semester average by passing the current row of grades (i.e., grades[ student ]) to member function getAverage.

Fig. 7.25. Creates a GradeBook object using a two-dimensional array of grades, then invokes member function processGrades to analyze them.

 

 1   // Fig. 7.25: fig07_25.cpp
 2   // Creates GradeBook object using a two-dimensional array of grades.
 3
 4   #include "GradeBook.h" // GradeBook class definition
 5
 6   // function main begins program execution
 7   int main()
 8   {
 9      // two-dimensional array of student grades
10      int gradesArray[ GradeBook::students ][ GradeBook::tests ] =
11        { { 87, 96, 70 },
12          { 68, 87, 90 },
13          { 94, 100, 90 },
14          { 100, 81, 82 },
15          { 83, 65, 85 },
16          { 78, 87, 65 },
17          { 85, 75, 83 },
18          { 91, 94, 100 },
19          { 76, 72, 84 },
20          { 87, 93, 73 } };
21
22     GradeBook myGradeBook(
23        "CS101 Introduction to C++ Programming", gradesArray );
24     myGradeBook.displayMessage();
25     myGradeBook.processGrades();
26      return 0; // indicates successful termination
27   } // end main

					  

 

Welcome to the grade book for
CS101 Introduction to C++ Programming!

The grades are:

             Test 1  Test 2  Test 3   Average
Student  1       87      96      70     84.33
Student  2       68      87      90     81.67
Student  3       94     100      90     94.67
Student  4      100      81      82     87.67
Student  5       83      65      85     77.67
Student  6       78      87      65     76.67
Student  7       85      75      83     81.00
Student  8       91      94     100     95.00
Student  9       76      72      84     77.33
Student 10       87      93      73     84.33

Lowest grade in the grade book is 65
Highest grade in the grade book is 100

Overall grade distribution:
  0-9:
10-19:
20-29:
30-39:
40-49:
50-59:
60-69: ***
70-79: ******
80-89: ***********
90-99: *******
  100: ***

					  


Member function getAverage (lines 105–115) takes two arguments—a one-dimensional array of test results for a particular student and the number of test results in the array. When line 174 calls getAverage, the first argument is grades[ student ], which specifies that a particular row of the two-dimensional array grades should be passed to getAverage. For example, based on the array created in Fig. 7.25, the argument grades[ 1 ] represents the three values (a one-dimensional array of grades) stored in row 1 of the two-dimensional array grades. A two-dimensional array can be considered an array whose elements are one-dimensional arrays. Member function getAverage calculates the sum of the array elements, divides the total by the number of test results and returns the floating-point result as a double value (line 114).

Testing Class GradeBook

The program in Fig. 7.25 creates an object of class GradeBook (Figs. 7.237.24) using the two-dimensional array of ints named gradesArray (declared and initialized in lines 10–20). Note that line 10 accesses class GradeBook's static constants students and tests to indicate the size of each dimension of array gradesArray. Lines 22–23 pass a course name and gradesArray to the GradeBook constructor. Lines 24–25 then invoke myGradeBook's displayMessage and processGrades member functions to display a welcome message and obtain a report summarizing the students' grades for the semester, respectively.