Lab 14: Two-Dimensional Arrays

Click Here to CREATE ANSWER SHEET for Lab 14

Objectives:

Sections:

  1. Introduction to Two-Dimensional Arrays
  2. Declaration of Two-Dimensional Arrays
  3. Accessing a Two-Dimensional Array Element
  4. Two-Dimensional Array Initialization
  5. Two-Dimensional Arrays as Function Parameters
  6. Two-Dimensional Array Processing
Introduction to Two-Dimensional Arrays
Two-dimensional arrays, the most common multi-dimensional arrays, are used to store information that we normally represent in table form. Two-dimensional arrays, like one-dimensional arrays, are homogeneous; this means that all the data in a two-dimensional array is of the same type. Examples of applications involving two-dimensional arrays include:
Declaration of Two-Dimensional Arrays
Example: The following declarations set aside storage for a two-dimensional array called labScores that contains 40 rows and 14 columns. Rows correspond to a particular student and columns correspond to a particular lab score.

	const int MAX_STUDENTS=40;
	const int MAX_LABS=14;

	int labScores[MAX_STUDENTS][MAX_LABS];

Exercise 1:
Show C++ statements to declare the following two-dimensional array:

Declare a two-dimensional array that can be used to store a yearly budget. Each row of the array corresponds to a particular budgeted item like rent, electric, etc. There are at most 15 items to be budgeted. Each column of the array corresponds to a month, January, February, etc. Of course there are 12 columns corresponding to the 12 months of the year. All the data to be placed in the array consists of real numbers.

Manipulation of a two-dimensional array requires the manipulation of two indices. When the two-dimensional array labScores is declared, enough storage is set aside to hold a table containing 40 rows and 14 columns for a total of 40 * 14 = 560 integer values. To access one particular value, we must specify the row and column. The row index ranges from 0 to MAX_STUDENTS-1 (39) and the column index ranges from 0 to MAX_LABS-1 (13). Thus the table can be visualized as:

This two-dimensional array may also be visualized as a one-dimensional array of arrays. An alternative view of this array would be:

 

This two-dimensional array may be viewed as a one-dimensional array having 40 elements where each element is an array of 14 values.

Accessing a Two-Dimensional Array Element
In our labScores example, suppose we wish to indicate that the second student (corresponding to row 1) made a 90 on lab 10 (corresponding to column 9). We might use the statement:

labScores[1][9] = 90;

Array indices may be integer constants (as in the above example), variables, or expressions. They should be within the bounds of the array.   (Important: Just as with one-dimensional arrays, C++ does not do run-time bounds checking of indices.)

  Two-Dimensional Array Initialization
We can declare and initialize an array A as follows:


	//declaration
	int A[3][4] = {{8, 2, 6, 5},     //row 0
		      {6, 3, 1 ,0},      //row 1
		      {8, 7, 9, 6}};     //row 2


Memory for the array may be visualized as:



Exercise 2: a. After the final answer sheet is printed, draw an alternative visualization of memory for the array A as we did above for our lab scores example.

b. What value is stored in row index 2, column index 1?

c. Give the name of the location where the value 0 is stored?


When we store or process an array row-by-row, rather than column-by-column, we call that row-major ordering. We usually, but not always, process two-dimensional (2-D) arrays in row-major order.

We may also fill the elements of a 2-D array by reading data. Suppose we wish to read entries into our labScores array. We should use two loops--one to control the student (row) and one to control the lab (column). For example, to read in all labs corresponding to the first student (the data in the first row of the table), then read in all labs corresponding to the second student (the next row), and so on, we might use the following function:

//Function:    ReadScores()
//Purpose:     This function inputs lab scores for
//             students in a computing class.
//

void ReadScores(int labScores[MAX_STUDENTS][MAX_LABS], //OUT: student labs
                int& numStudents,                       //OUT: actual # of students
                int& numLabs,                           //OUT: actual # of labs
                ifstream& myin)                         //IN:  input file stream
{
   //local variables
   int student, lab;        //index for the student and lab being processed

   //first read the number of students and labs
   //stored in the file.
   myin >> numStudents >> numLabs;

   //Outer loop controls which student (row) is being read
   for (student = 0; student < numStudents; student++)
   {
       //Inner loop controls which lab (column) is being read
       for (lab = 0; lab < numLabs; lab++)
            myin >> labScores[student][lab];
   }
   return;
}




Exercise 3:
Suppose we wish to read in the data for our students' scores but the file is organized differently. Instead of all of one student's labs appearing first, the file has all grades on lab 1 first, then all grades on lab 2, etc. (In other words, the data is organized in column-major order.) How must the code above be changed to accommodate this new arrangement of data? Explain the difference on the answer sheet.
Two-Dimensional Arrays as Function Parameters
As with one-dimensional arrays, a two-dimensional array is automatically passed as a pass-by-reference parameter. Consider the
function heading above. The following function heading also could have been used:


   void ReadScores (int labScores[][MAX_LABS],      //OUT: student labs
                    int& numStudents,               //OUT: Number of students
                    int& numLabs,                   //OUT: Number of labs 
                    ifstream& myin);                //IN:  Input file stream

Notice the difference between these two function headings. For the labsScores array, the second heading does not include the number of rows required by the array but does include the number of columns. The explanation is simple -- when we pass an array the compiler need only know the size of its elements, not how many elements it has. As explained above, a two-dimensional array can be thought of as a one-dimensional array of elements (that just happen to be arrays themselves). Thus the compiler needs to know the size of one of the elements. Each element is a row of values so the compiler needs to know the type of elements and how many values (the number of columns) are in each row. In the labScores array, the number of columns is MAX_LABS.

This second function heading, with the empty row value in the declaration, is the preferred way of declaring a 2-D array parameter.

If one wants to print the entire set of scores, a nested loop similar to that above can be used.




Exercise 4:
Copy the program cla14a.cpp and the data file labscores.dat to your account. This program contains declarations for the labScores array and contains a function that reads in data into this array from the file labscores.dat. Make sure that you understand the code included in the program.

Add a function to print the scores so that each student's labs appear on a separate line of output. Include a statement in your main program to call this function. Your output should be labeled as follows:


	Student 1:  80  90  70  100  60  90  85  78  93  80  70  98  89  94
	Student 2:  98  85 100   99  89  90  72   0  78  98 100  65   0  56
	Student 3:  85  60  25....
	.
	.
   
Compile and run your program to make sure it is error free.

Two-Dimensional Array Processing
Processing of two-dimensional arrays might include finding an average of a row or a column. Suppose in our lab scores problem, we wish to determine the lab average for the third student (remember, this means row 2). The solution to this problem consists of finding the sum of all of the entries in row index 2 and dividing by the number of labs, NUM_OF_LABS.

	15   sum = 0;
	16   student = 2;	// 3rd student
	17   for (lab = 0; lab < NUM_OF_LABS; lab++)
	18        sum += labScores[student][lab];
	19   average = float(sum)/NUM_OF_LABS;
	20   cout << "The average for student " << student+1 << " is " 
	21   << average << endl;


In general, if we wished to determine the average for the Kth student, then K-1 would replace the value 2 in statement 16 above. If we wished to find an average for all 40 students, we can add an outer loop to control the student index.



Exercise 5:

Add a function to your copy of cla14a.cpp, called StudentAvg(), that finds and prints the lab average for each student in the class. A function prototype for this function is shown below. Call this function from the main program. Compile and run your program.


   void StudentAvg(int labScores [][MAX_LABS],  //IN:  Lab scores
                   int numStudents,             //IN:  # of students in the class
                   int numLabs)                 //IN:  # of labs recorded per student
	         


Exercise 6:
Add a function to cla14a.cpp, called labAvg(), that finds and prints the average score made on each individual lab. Call this function from the the main program. Compile and run your modified program. Submit a script log of a listing, compile, and run. The following UNIX commands will let you create what is required:

            $ script lab14ex6.log
            $ pr -n -t -e4 cla14a.cpp
            $ c++ cla14a.cpp -o cla14a
            $ cla14a
            $ exit
(Be sure to exit the script session before continuing!)


Exercise 7:

Submit the log file you have created in Lab 14 typing

          $ handin lab14log lab14ex6.log
Exercise 8:

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


Congratulations! You have finished Lab 14.



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.