Search

6.3 — Arrays and loops

Consider the case where we want to find the average test score of a class of students. Using individual variables:

That’s a lot of variables and a lot of typing -- and this is just 5 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 totalScore calculation. Any time you have to modify old code, you run the risk of introducing errors.

Using arrays offers a slightly better solution:

This cuts down on the number of variables declared significantly, but totalScore still requires each array element be listed individually. And as above, changing the number of students means the totalScore formula needs to be manually adjusted.

If only there were a way to loop through our array and calculate totalScore directly.

Loops and arrays

In a previous lesson, you learned that the array subscript doesn’t need to be a constant value -- it can be a variable. This means we can use a loop variable as an array index to loop through all of the elements of our array and perform some calculation on them. This is such a common thing to do that wherever you find arrays, you will almost certainly find loops! When a loop is used to access each array element in turn, this is often called iterating through the array.

Here’s our example above using a for loop:

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 calculations do not have to be manually altered to account for new students, and we do not have to manually add the name of new array elements!

Here’s an example of using a loop to search an array in order to determine the best score in the class:

In this example, we use a non-loop variable called maxScore to keep track of the highest score we’ve seen. maxScore 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 maxScore to that value. Thus, maxScore always represents the highest score out of all the elements we’ve searched so far. By the time we reach the end of the array, maxScore holds the highest score in the entire array.

Mixing loops and arrays

Loops are typically used with arrays to do one of three things:
1) Calculate a value (e.g. average value, total value)
2) Search for a value (e.g. highest value, lowest value).
3) Reorganize the array (e.g. ascending order, descending order)

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, totalScore holds the total score for all the elements examined so far.

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, maxScore is used to hold the highest score encountered so far.

Sorting an array is a bit more tricky, as it typically involves nested loops. We will cover sorting an array in the next lesson.

Arrays and 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 length of the array can have dire consequences. Consider the following program:

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:

But scores[5] is undefined! This can cause all sorts of issues, with the most likely being that scores[5] results in a garbage value. In this case, the probable result is that maxScore will be wrong.

However, imagine what would happen if we inadvertently assigned a value to array[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:

Hint: You can use the sizeof() trick to determine the array length.

2) Given the array in question 1:

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.

You can test std::cin for invalid input by using the following code:

3) Modify the following program so that instead of having maxScore hold the largest score directly, a variable named maxIndex holds the index of the largest score.

Quiz solutions

1) Show Solution

2) Show Solution

3) Show Solution

6.4 -- Sorting an array using selection sort
Index
6.2 -- Arrays (Part II)

148 comments to 6.3 — Arrays and loops

  • Satwant

    Quiz 3 has a type error.  
    if (scores[student] > scores[maxIndex]

    Max index not defined,  I think should be maxScore

  • Aaron

    I’m having trouble understanding this section of code.

    What is the function of (std::cin.fail()? How does it know what a valid input is, if it hasn’t been told what is valid?
    Also, why is std::cin >> number; able to change the value of int = number; when it’s outside of block scope?

    • Alex

      When we try and do an extraction operation (using operator >>) such as this:

      … the following will happen:
      1) If there is no unprocessed input in cin, the user will be asked to enter something
      2) cin will attempt to extract data from the input stream into variable number
      3) If this fails, an internal flag will be set to indicate the failure. A failure will occur if the data is not the correct type for the variable being extracted to (such as trying to extract a letter into an integer variable).

      std::cin.fail() allows us to access this error flag, and returns a boolean indicating whether an error has occurred previously.

      > Also, why is std::cin >> number; able to change the value of int = number; when it’s outside of block scope?

      It’s not outside the block scope. number is declared within the block of the function, and only used within the block of the function. It is legal to access values from within a nested block. You get into trouble when you define a variable inside a block and try to access it outside of that block. A nested block doesn’t count as “outside”.

  • Mr D

    Wait, sorry, silly me, now i understand, you want to hold the index of the largest score, rather then the actual score!!

  • Mr D

    A question about quiz 3:

    In line 9 of the solution you have:

    but wouldn’t it have been simpler just to write:

    ????
    In your method you choose to compare each successive index to the first index [maxIndex == 0 == score of 84], but isn’t it simpler to just compare it directly to manIndex(0) as you did in an earlier example?

    By the way, in the code of the question part of quiz 3, shouldn’t line 9 read:

    ??
    As it is now, it doesn’t compile!

  • Mr D

    Hi Alex,

    What is the purpose of the code (quoted below)?

    The quiz 2 program executes exactly the same, with or without it!

    • Gio

      I’m having trouble wrapping my head around the purpose of this code as well. If I comment it out, the program seems to run the exact same without it, as far as I can tell.

      On a side note, Alex,  this is my first time posting to this site, so I wanted to take the chance to say that these have been the most comprehensive programming tutorials I’ve ever delved into. Most other ones tend to throw users into learning if statements and loops in the very beginning without properly explaining things like #include <iostream> from the get go. Your progression of the lessons feels very spot-on and natural. Thank you!

      • Alex

        As I noted to Mr. D, the example was broken. 😐 It’s fixed now.

        Glad to hear you’re enjoying the lessons. Part of the reason they’re great is because of all the wonderful feedback readers have left me over the years! 🙂

    • Alex

      It was supposed to handle the user entering an invalid input (e.g. ‘p’), but I made a mistake in the code so it didn’t work correctly. I’ve updated the example. It should work now.

  • This will print the best score and its index for question #3:
    =================================================
    // chap6.3ques3.cpp : Defines the entry point for the console application.
    //

    #include "stdafx.h"

    #include <iostream>

    int main()
    {
        const int numStudents(5);
        int scores[numStudents] = { 84, 92, 76, 81, 56 };
        int maxIndex = 0;
        int maxScore = 0; // keep track of our largest score
        for (int student = 0; student < numStudents; ++student) {
            if (scores[student] > maxScore) {
                maxScore = scores[student];
                maxIndex = student;
            }
        }
        std::cout << "The best score was " << maxScore << ", and its index is " << maxIndex << ‘\n’;

        return 0;
    }

  • Question 2 quiz solution crashes if user gives it a letter instead of an integer! I always have trouble with "cin"! Apparently the special code to protect the buffer does not work.

    • Alex

      Where is it crashing? You should be able to use the debugger to step through and determine what line it’s crashing on. Once we know where it’s crashing, then we can figure out why.

  • Quang

    I think the solution for Quiz#1 has a problem, it should be arrayLength not arraySize Alex!
    Btw thank you so much for this great tutorial!

  • Eric

    I have really tried, but can’t find out what’s wrong in my code. If I enter a character instead of an integer the while loop gets stuck and cin.fail() triggers every time without letting me enter a new character/number. How can this happen when I used cin.ignore() and then clear the error flags with cin.clear()?

    • Eric

      Finally! Placing cin.clear() before cin.ignore() solved the problem. Seems like I had to clear the error flags before emptying the input buffer or else the buffer was not emptied? Does someone know why?

      …and thanks for a great tutorial Alex! I really like the quizzes and hope that you will find the time to add more summarizing quizzes to the end of the remaining chapters 😉

      • Alex

        Once cin is in the error state, it ignores other function calls until the error is cleared. Otherwise the output of those calls would be unreliable, as the stream might not be in a valid state.

  • Ishana

    #1 on the quiz, I don’t understand why using sizeof() function (instead of 9) in the for loop, gives a lot more bunch of numbers after the array is printed?

    • Alex

      Using sizeof on a fixed array returns the total size of the array (array length * element size). What you really want is the array length.

      The easiest way to do this is set the array length as a const int, and then use that. I’ve updated the quiz to use this method.

  • Shane

    I found question 3 somewhat confusing due to its wording when it said print the array, what array?

    If question 2 was not in the middle it would have made much more sense.

  • The correct solution for #2 will be:

    You forgot to write "std::" before cout + In quiz #3, you asked to write this to handle invalid input:

    Note the ‘n’ part in line 4. In the solution, you just wrote std::cin.ignore(32767).
    Thanks Alex…You are doing great.

  • When does std::cin.fail() evaluates to true in the #2 solution?

  • Viv

    I think this is a mistake?

    In the solution number two (modifying the piece of code), in the if statement, you are comparing “score[student]” to “maxScore”, which is no longer a declared variable since it was changed to maxIndex and shows up as an error. In the code to be modified in the original problem, the value being compared is “score[maxIndex]”, which in that case is not a declared variable, and which is what should be in the solution. I think these may have been switched?

  • MysteryLight

    Hi Alex!
    I’ve been writing code about Rock Paper Scissors with Arrays, and I want to know your idea about this code.
    Here is my code.

    What do you think?

    • MysteryLight

      sorry for bother i have use Arrays but don’t call them. This is my problem. my brother told to me that my code is wrong, so i check again and find this.

      • Alex

        Other issues:
        * rock_peper_scissors has a poor name.
        * as you’ve noted, you never use an array (I don’t know why you need it, just code the logic in main or in a function)
        * your function to do rand_range is very inefficient (I show a better method in lesson 5.9)
        * your input error handling doesn’t handle negative numbers

  • Regarding the problem in question #2, when a non-numeric character is entered, I found a solution by doing the while loop using character values then converting the character input to a numeric by substracting 48. See my code below:

    //  Created by Cliff on 3/10/15.
    //  Copyright (c) 2015 Cliff. All rights reserved.
    //

    #include <iostream>

    int main() {
        
        using namespace std;
        char cInput(0);
        
        int anNumbers [9] {4,6,7,3,8,2,1,9,5};
        
        //Get user input
        do
            {   cout << " Please enter a number between 1 and 9 n";
                cin >> cInput;
            }
            while (cInput < ‘1’ || cInput > ‘9’); //Using char type to keep from loop with non-numeric input.
        
        // Print array
                for (int iii = 0; iii < 9; iii++)
                cout << anNumbers [iii] << " ";
        
        // Search array for user entered number to get index value.
        int jjj(0);
        cout <<endl;
        for (jjj=0; anNumbers[jjj] != cInput - 48; jjj++)
            ;
        // Print index
        cout << jjj + 1 << endl;
        
        return 0;
    }

  • it is a very good site to learn cpp programming.

  • Silvia

    For 6.3 — Arrays and loops - 2nd Quiz: If I run your code, and enter any letter instead of a number, it loops infinitely on printing the request. Why? (Entering any number other than 1..9 it works instead: it properly stops on asking)

    • Alex

      When you enter a non-integer, cin tries to extract this character into the integer variable but fails. The non-integer character is left in the stream. The loop conditions cause it to loop back to cin, and try again. But since the previous characters are still in the stream, cin tries to read them again, and fails again. It does this over and over.

  • Jesper

    Hey - the below code is copy pasted directly from Microsoft Visual 2010 and as far as i can see its exactly the same as the solution Alex posted.

    I’m new to learning c++, and I’m really enjoying following this tutorial.

    My question is this:
    When i run the program it correctly keeps asking for a number between 1 and 9 as long as i input a number when prompted. However if I input a letter (Tried it to see what would happen incase of a misstype) it seems to go into an endless loop. Is it supposed to do that (with the code written) or is there another way to avoid this problem I should implement?

    • Slotenmaker

      I had the same problem, it is because of cin.
      cin tries to stream a character inside an integer, which will fail. But the stream will stay in memory! So the next loop it will again try the same character, and again, and again, etc.

      If you put this code in the while loop it fixes this problem, you will also have to #include .
      It clears the stream:

      cin.clear();
      cin.ignore(numeric_limits<streamsize>::max(), '\n');

      Also you can use strings as an alternative.

  • Sagar

    [code] In solution number 2, shouldn’t it be nNumber > 1 || nNumber < 9 ?

    • Sergio Ramos

      No because that’s how the “Do While” loop works. A “Do While” loop will perform the “Do” statement (the request for a number 1 to 9) so long as it’s condition is true. So you want it to be false.

      Say, if nNumber is less than 1 or greater than 9, the entire condition will be true and the “Do While” statement will repeat, until the entire condition becomes false. !(9) or (>1 && <9).

      Review the "De Morgan’s law" section of "3.6 - Logical Operators" for further information.

  • Mattias

    For the second question, would this also work? (When each element in the array has a unique value of course)
    If it has any downsides please let me know.

  • Matthew

    I’m getting a “syntax error : ‘<‘” when I try to compile; it’s pointing to this line:

    My code looks the same as yours!!!! This is driving me nuts! What have I done wrong?

  • Mithrildor

    I made this one for question 2 is this oen right too?

    It looks easir to understand to me.

  • Shai

    I’ve already fixed the following silly problem, but I thought I might as well share it 🙂

    It’s just wrong to try to do too many things with one variable. 😛

    It left me baffled for a while because most user inputs would print the correct element!

    • Yup, generally speaking it’s good to have a variable keep track of one and only one thing. Here, your nUserNum has two jobs: to accept the user input, and then later to store the index of the matching array element, which is a totally different thing!

      Although it may have taken you a while to find and fix the issue, it’s a good lesson to learn.

  • runner

    Isn’t it better to do the array printing and the searching in the same loop?

    Also, entering a char input is leading to an infinite loop, why?

    • For efficiency purposes, yes, it’s better to only loop through the array once instead of twice. I personally would have written it the way you did, but I opted for a quiz solution that conformed more closely to the way the question was worded.

      As to your infinite loop question, I answered that one here. The issue here is the same.

  • Ben

    So trying to access an undefined array value (like

    in your example) will not return a compiler error?
    How come? It seems pretty dangerous.

    • anArray[5] won’t cause a compiler error, and it IS dangerous. C++ does not do any sort of compile-time bounds checking on it’s arrays -- and perhaps worse, it doesn’t do any runtime bounds checking either! This is one of those areas that definitely falls under “trust the programmer”.

      The underlying reason is due to the fact that arrays are implemented as pointers, and [] is implemented as a pointer addition operation. You’ll learn more about this in lesson 6.8.

      Once you learn about C++ classes, you’ll be able to write your own array classes that look and feel exactly like C++ built-in arrays, but can have additional safety features like runtime range checking.

  • Zak

    Thanks a lot for these very helpful tutorials! Much appreciated.

  • John

    The user is asked to enter a number between 1 and 9, but the array is indexed by 0 to 8, and the for loop runs from 0 to 8. This doesn’t make sense to me. Is this an error?

    • In C++, all arrays are 0-based, meaning the first element is numbered 0. In regular life, if we have 9 items, we’d count them like this: 1 2 3 4 5 6 7 8 9. However, in C++, we begin counting at 0, so we count 9 items like this: 0 1 2 3 4 5 6 7 8. That’s why the array is indexed 0 to 8.

      • Nikko

        Yes but for the above solution if you choose 9 the result come out like this:

        4 6 7 3 8 2 1 9 5
        The number 9 has index 7

        where did "7" come from. Index 7 should be array[2]

        • Alex

          An index is the value that goes inside the subscript ([] brackets). You’re using index and value synonymously, which is incorrect.

          Index: 0 1 2 3 4 5 6 7 8
          Array: 4 6 7 3 8 2 1 9 5
          

          You can see that the array element with value 9 has index 7.

    • Well, I actually used anArray[nNumber - 1] to give the correct element.

  • Tom

    Hello Alex -

    Would this also be a correct way to do the search?:

    Thanks!

    • Your code is not quite correct -- what happens if it doesn’t find the number the user entered? In that case, iii will be 10 when the loop exits, and your code will still print that the number has index 10, which is not a valid index.

      As an aside, using a for loop to iterate through an array is usually better than a while loop because it contains the initialization and increment all within one statement, making it less likely you’ll forget them.

  • Chad

    Shouldn’t you put a break in your if statement? If we know that each element of naArray is unique, we only need to search until we find what we want. Searching the rest of the array just wastes time.

    • Yup, if we can assume that each element of naArray is unique, then we could terminate the loop after finding an element that matches. I will clarify the solution.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter