CSC 306 Introduction to Programming with C++

Working with Arrays

Chapters 6 and 10.1 - 10.4


Objectives

Important Definitions


Arrays and Sorting

Although we have already seen how to store large amounts of data in files, we have as yet no convenient way to organize and manipulate large number of data within a program itself. For example, suppose we want to input from a file a large number of integers and then sort them in increasing or decreasing order. C++ provides a structured data type called an array to make this task easier. An array is similar to a structure in the sense that it is a group of variables combined as a single entity, but it differs because:

Declaring Arrays

The general syntax for an array declaration is:

data type variable name[integer value representing size];

When working on the assignment using files, recall the method used to store the filename that is input from the user...it is an array of chars:

char myFilename[10]; // create a variable called myFilename that consists of 10 chars

Each character is an element of myFilename, and each one can be accessed/referenced directly using its index, which is the position that element has in the array.
Warning: Remember that computers start counting from zero, so the index is one minus the position that you would automatically place the element. Therefore, the 4th letter of myFilename has the index of 3, so the reference is myFilename[3].

Another example of using arrays is to store information such as the number of miles per gallon each car out of group of 6 can get. When declaring an array, you can either (1) simply use an actual number (as the 10 did for myFilename above) to indicate how many cars are in the array or (2) use a constant identifier instead. The advantage of the second approach will be touched upon when we discuss modifying the elements of the array:

Simple Way Better Way

int mpg[6];
const int NUM_AUTOS = 6; // constants are often CAPITALIZED
int mpg[NUM_AUTOS];
Note that the identifier that specifies the number of elements in an array must be a const because you cannot use a variable size in an array declaration in most versions of C++, including the ANSI Standard.

Upon declaring the array as we have above, there are now 6 elements of type int that can be referenced as: mpg[0], mpg[1], mpg[2], mpg[3], mpg[4], mpg[5]. The computer allocates consecutive memory locations to the elements of this array, and they can be pictured as shown on the right:

Assignment Statements and Expressions with Array Elements

Having declared our array, we can treat the individual elements just like ordinary variables (of type "int" in the particular example above). For example, we can have the second car be able to drive 34 miles per gallon and the sixth car can only get half as far per gallon via the following assignment statements:

mpg[1] = 34;       // recall that the 2nd car has index of 2-1 = 1
mpg[5] = mpg[1]/2; // mpg[1] has the value 34 stored in it
They could also be used in logical expressions to define which branch a conditional statement should take, such as in the following example:

if( mpg[1] > 30 ) {
    cout << "Gas will be cheap for your second car!\n";
}
if( mpg[5] == 2 * mpg[1] ) {
    cout << "Gas will be twice as expensive for car number 6!\n";
}
A common way to assign values to an array is using a for or while loop (the for loop may make more sense here because you may think "for each element in the array, do <something>"). As with any program, the statements in the loop may be whatever you want. The following program prompts the user for the number of miles each car he/she owns drives per gallon. The two versions below perform the same operation. Whereas the left side has the loop structured in a more intuitive sense (first car has index of 1), the version on the right is closer to what the computer views array elements (the first element has index of 0).

Intuitive Version Computer's Version
#include <iostream>
using namespace std;

const int NUM_AUTOS = 6;
typedef int MPG_array[NUM_AUTOS];

int main() {
    MPG_array mpg;
    int count;

    // Start counting from 1 to 6
    for( count = 1; count <= NUM_AUTOS; count++ ) {
	cout << "Enter the MPG for vehicle ";
	cout << count << ": ";
	cin >> mpg[count - 1];
    }
	
    return 0;
}
#include <iostream>
using namespace std;

const int NUM_AUTOS = 6;
typedef int MPG_array[NUM_AUTOS];

int main() {
    MPG_array mpg;
    int count;

    // Start counting from 0 to 5
    for( count = 0; count < NUM_AUTOS; count++ ) {
	cout << "Enter the MPG for vehicle ";
	cout << count + 1 << ": ";
	cin >> mpg[count];
    }
	
    return 0;
}
There are several things to note here. First, we used the keyword typedef on the fifth line (shown in red) to let the compiler know that we are equating the word MPG_array to mean the same as the "int [NUM_AUTOS]" variable type (i.e. an array). Secondly, by using the constant variable NUM_AUTOS when declaring the array, we can use the same constant to control the loop index to make sure we stay within the defined loop bounds. Finally, the loop on the left side subtracted one from the index before accessing the data located there because the counter variable for the loop started from one and went to six. The version on the right version added a one before asking the user for the miles per gallon because the expected way to count cars is from one to six. The reference to the array element is still from zero to five in either case, however.

A typical run of this program might produce the following input and output:

Enter the MPG for vehicle 1: 34
Enter the MPG for vehicle 2: 10
Enter the MPG for vehicle 3: 15
Enter the MPG for vehicle 4: 20
Enter the MPG for vehicle 5: 49
Enter the MPG for vehicle 6: 14
Ensuring that the references to the array stay within the expected indexes highlight an insidious yet vital fact about C++: it does not perform range checking for illegal out-of-range index accesses. This results in weird program behavior. Suppose this program accidentally assigned a value to mpg[6] (the seventh car, when only six were defined). What does that operation mean and more importantly, what does it do? The program would have simply put that value, be it 1000, 0, or 2, into the next integer-sized chunk of memory located after the memory block set aside for the array. Although this may seem to be a harmless act, it results in a very undesirable situation - the compiler might have already reserved this chunk of memory for another variable, and now it has changed even though the programmer did not intend it to be modified. The behavior of the program is then unpredictable and odd and rather difficult to debug.
WARNING A common error is to resize the array but forget to change the range of indexes that your program accesses, either in a loop or directly. Consider the following code fragment:
int main() {
    int mpg[6];
    int count;

    // set the mpg's for all six autos to zero.
    for( count = 0 ; count < 6; count++ ) { mpg[count] = 10; }
...
    // divide all six elements of the mpg array by two.
    for( count = 0 ; count < 6; count++ ) { mpg[count] = mpg[count]/2; }

...
    // set the last mpg to 10, assuming 6 elements in the array
    mpg[5] = 10;
}
Suppose later, you decide that you only need to store the information for five cars and change the array declaration to:

    int mpg[5];
There are now three more places in the program you must update to ensure that you will not modify memory locations that are not part of the array; the two loops and the last statement of the main() function. Although this may seem to be a simple thing to do, it is rather difficult as your program becomes more complicated.

By using a constant when declaring an array, you can use the same constant to define loop bounds, so the size of the array and loop bounds change automatically:

const int NUM_AUTOS = 6;
int main() {
    int mpg[NUM_AUTOS];
    int count;

    // set the mpg's for all autos to zero.
    for( count = 0 ; count < NUM_AUTOS; count++ ) { mpg[count] = 10; }
...
    // divide all the mpg's by two.
    for( count = 0 ; count < NUM_AUTOS; count++ ) { mpg[count] = mpg[count]/2; }

...
    // set the last mpg to 10... it now really means the last one
    mpg[NUM_AUTOS-1] = 10;
}

Arrays using Chars

The following program reads the first 1000 characters of a file and then prints the them out backwards on the screen. The characters are stored in an array of type char.

#include <iostream>
#include <fstream>

using namespace std;

const int MAX = 1000;
char store[MAX];

int main() {
    char character;
    int count;
    ifstream in_stream;

    in_stream.open("data.cpp");
    in_stream.get(character);

    // Read the first MAX (1000) characters from the file and store in file
    for( count = 0 ; ! in_stream.eof() && count < MAX ; count++ ) {
    	store[count] = character;
    	in_stream.get(character);
    }

    in_stream.close();

    // Now output the chars onto the console.
    while (count > 0)
	cout << store[count--];

    return 0;
}
The use of the condition "!in_stream.eof() && count < MAX" at the head of the for loop avoids the possibility of a range bound error.

Arrays as Function Parameters

Functions can be used with arrays as inputs, but a formal parameter for an array is neither a call-by-value nor a call-by-reference. Instead, it is a new type of parameter called an array parameter that lets the compiler know that the argument is going to be an array, and the syntax is:

data type name[]
The following function takes as input an array of integers and the number of elements it contains and returns the average. Note that the average is a double value, so the return type is set to that as well.

// It is correct syntax to omit the length of the array in the parameter, 
// so that information must be passed in as a separate parameter.
double average( int list[], int length ) {
    double total = 0;
    int count;
    for( count = 0 ; count < length ; count++ )
	total += double(list[count]);
    return (total / length);
}
Although array parameters are not declared with an ampersand indicating a parameter by reference (an "&"), they are effectively like call by reference parameters. In other words, when the functions execute with array parameters, they do not make private copies of the arrays they are passed because doing so this would potentially be very expensive in terms of memory.
WARNING Array elements can always be permanently changed when passed as arguments to functions unless the const modifier is included in the parameter declaration.

Consider the following function that takes as input three arrays in which the third one will contain the sum of the corresponding elements of the first two:

s
// This function assumes that the length of the three arrays are the 
// same. OTHERWISE A LOGICAL ERROR CAN OCCUR!
void add_lists( int first[], int second[], int total[], int length ) {
    int count;
    for( count = 0 ; count < length ; count++ )
	total[count] = first[count] + second[count];
}
Nothing precludes (prevents) the programmer from inserting the statement

	first[count] = first[count] * 10;
even if that is not what the function is designed to perform. A programmer could have easily left that statement in there while editing the source code. Adding the modifier const to the first two array parameters acts as a safety measure to prevent unintended consequences of calling add_lists(...):

// The elements of first and second are now constants
void add_lists(const int first[], const int second[], int total[], int length) {
    int count;
    for( count = 0 ; count < length ; count++ ) {
	total[count] = first[count] + second[count];
	first[count] = first[count] * 10;
    }
}
The compiler will not not accept any statements that can potentially modify the elements of the arrays first or second and will show an error on line 6, indicated in blue.


Assignment Specifics

This assignment must be completed individually.

For this assignment, you are to create a class that can be used to handle a large set of integer data. An object in this class has a array member variable that is guaranteed to contain no more than 100 integers. The user is presented various options to use, insert values and display this array.

Notes:

When you are finished writing and testing your assignment, drop the file with your source code, YourLastName_306A17.cpp, into the CSC306_A17 dropbox on the Academic server.


Back to Introduction to Computer Programming with C++ Homepage