Free Hosting

Arrays and loops


Loops and arrays
Because array elements can be accessed by a variable, it is common to use a loop to access or manipulate each array element in turn. Wherever you find arrays, you will almost certainly find loops as well.
Consider the case where we want to find the average test score of a class of students. Using individual variables:
1
2
3
4
5
6
7
8
9
const int nNumStudents = 5;
int nScore0 = 84;
int nScore1 = 92;
int nScore2 = 76;
int nScore3 = 81;
int nScore4 = 56;
 
int nTotalScore = nScore0 + nScore1 + nScore2 + nScore3 + nScore4;
double dAverageScore = static_cast<double>(nTotalScore) / nNumStudents;
That’s a lot of variables and a lot of typing — and this is just 4 students! Imagine how much work we’d have to do for 30 students, or 150.
Plus, if a new student is added, a new variable has to be declared, initialized, and added to the nTotalScore calculation. Any time you have to adjust old code, you run the risk of introducing errors.
Using arrays without loops offers a slightly better solution:
1
2
3
4
const int nNumStudents = 5;
int anScores[nNumStudents] = { 84, 92, 76, 81, 56 };
int nTotalScore = anScores[0] + anScores[1] + anScores[2] + anScores[3] + anScores[4];
double dAverageScore = static_cast<double>(nTotalScore) / nNumStudents;
This cuts down on the number of variables declared significantly, but nTotalScore still requires each array element be listed individually. Furthermore, changing the number of students means the nTotalScore formula needs to be adjusted.
Using arrays with loops:
1
2
3
4
5
6
7
const int nNumStudents = 5;
int anScores[nNumStudents] = { 84, 92, 76, 81, 56 };
int nTotalScore = 0;
for (int nStudent = 0; nStudent < nNumStudents; nStudent++)
    nTotalScore += anScores[nStudent];
 
double dAverageScore = static_cast<double>(nTotalScore) / nNumStudents;
This solution is ideal in terms of both readability and maintenance. Because the loop does all of our array element accesses, the formulas adjust automatically to account for the number of elements in the array. This means the formulas do not have to be manually altered to account for new students, and we do not have to manually enter the name of each array element!
Here’s another example of using a loop with an array to determine the best score in the class:
1
2
3
4
5
6
7
8
const int nNumStudents = 5;
int anScores[nNumStudents] = { 84, 92, 76, 81, 56 };
int nMaxScore = 0;
for (int nStudent = 0; nStudent < nNumStudents; nStudent++)
    if (anScores[nStudent] > nMaxScore)
        nMaxScore = anScores[nStudent];
 
cout << "The best score was " << nMaxScore << endl;
In this example, we use a non-loop variable called nMaxScore. nMaxScore is initialized to 0 to represent that we have not seen any scores yet. We then iterate through each element of the array, and if we find a score that is higher than any we’ve seen before, we set nMaxScore to that value. Thus, nMaxScore always represents the best score out of all the elements we’ve searched so far. By the time we reach the end of the array, nMaxScore holds the highest score in the entire array.
Loops are typically used with arrays to do one of three things:
1) Search for a value (eg. highest, lowest).
2) Calculate a value (eg. average, total)
3) Reorganize the array (eg. sort from lowest to highest)
When searching for a value, a variable is typically used to hold the best candidate value seen so far (or the array index of the best candidate). In the above example where we use a loop to find the best score, this variable is used to hold the highest score encountered so far.
When calculating a value, a variable is typically used to hold an intermediate result that is used to calculate the final value. In the above example where we are calculating an average score, nTotalScore holds the total score for all the elements examined so far. This value is then later used to calculate the overall average score.
Sorting an array is a bit more tricky, as it typically involves nested loops. We will cover sorting an array in the next lesson.
Off-by-one errors
One of the trickiest parts of using loops with arrays is making sure the loop iterates the proper number of times. Off-by-one errors are easy to make, and trying to access an element that is larger than the size of the array can have dire consequences. Consider the following program:
1
2
3
4
5
6
const int nArraySize = 5;
int anArray[nArraySize ] = { 6, 8, 2, 4, 9 };
int nMaxValue = 0;
for (int nIndex = 0; nIndex <= nArraySize; nIndex++)
    if (anArray[nIndex] > nMaxValue)
        nMaxValue = anArray[nIndex];
The problem with this program is that the conditional in the for loop is wrong! The array declared has 5 elements, indexed from 0 to 4. However, this array loops from 0 to 5. Consequently, on the last iteration, the array will execute this:
1
2
if (anArray[5] > nMaxValue)
    nMaxValue = anArray[5];
But anArray[5] is undefined! This can cause all sorts of issues, with the most likely being that anArray[5] results in a garbage value. In this case, the probable result is that nMaxValue will be wrong.
However, imagine what would happen if we inadvertently assigned a value to anArray[5]! We might overwrite another variable (or part of it), or perhaps corrupt something — these types of bugs can be very hard to track down!
Consequently, when using loops with arrays, always double-check your loop conditions to make sure you do not introduce off-by-one errors.
Quiz
1) Print the following array to the screen using a loop:
1
int anArray[9] = { 4, 6, 7, 3, 8, 2, 1, 9, 5 };
2) Ask the user for a number between 1 and 9. If the user does not enter a number between 1 and 9, repeatedly ask for a number until they do. Once they have entered a number between 1 and 9, print the array. Then search the array for the number that the user entered and print the index of that element.

0 comments:

Blogger Template by Clairvo