# 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 an integer value until they do. Once they have entered a number between 1 and 9, print the array. Then search the array for the value 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

### 232 comments to 6.3 — Arrays and loops

• Terra'Navis

I did question 2 a lot differently, could someone tell me if there is anything wrong/mal practice with the way i chose to do it:

• Hi!

* Line 18: This is personal preference, I prefer to only use "else if" if the conditions are related to each other. If they're not, I use "else" with a nested if-statement.
* Line 12, 20, 25, 27: Initialize your variables to a specific value (0)
* Line 31: The line feed should be printed in line 24 to leave the stream in a state in which it's easy to work with. If the loop in line 27 doesn't find the value, the caller will be left in the same line.
* Inconsistent formatting. Use the auto-formatting feature of your editor.

You did what the quiz asked for, but thinking about it, it should be "from 1 to 9", not "between 1 to 9".

• Terra'Navis

hi nascardriver,
thanks for your input, useful as usual

i was just wondering, what the inconsistent formatting your seeing is, i even tried putting the code back into visual studio and using the manual format document, and i couldn't see anything change

also i actually did the numbers from 1 to 9, then looked at alex's solution and he had done them between 1 and 9 so i changed it

thanks

• Line 14 has the opening curly bracket in the same line. Line 18 has it in the next line.
Also, line 20 and 27: Use ++prefix

• Terra'Navis

awesome, thanks for pointing that out

My Solutions
1)

2)

3)

please point out bugs and other shortcomings in the code 🙂

All)
* Initialize your variables with uniform initialization.
* If a conditional statement exceeds 1 line, use curly brackets.
* Use ++prefix unless you need postfix++

2)
* Don't use goto, cpp has enough easier to read control structures of achieving the same.
* Gets stuck in an infinite loop on invalid input
* Use @std::numeric_limits<std::streamsize>::max() instead of 32767. See the documentation of @std::basic_istream::ignore.

Thanks

• The next one took a little more thinking:

* Line 9: while wants a bool, 1 is an int, use

* Line 16: Good
* Line 26: Uniform initialization
* Line 27, 30: ++prefix
* Line 31-35: Wrap in curly brackets

• Hi

Even remembering to use uniform initialisation now 🙂

• Hi Nigel!

> Even remembering to use uniform initialisation now
Thank you!

* Line 11: Uniform initialization
* Line 12: Declaration of @count should be moved into the for loop's header
* Line 13: Use ++prefix unless you need postfix++

• Hi,

when I did this initially:

Visual Studio complained that count wasn't declared so I used a separate declaration on line 12.

• Winston Lai

Hi, I was trying to do the second problem on the quiz, and I was trying to set up the if statement for the operation mode in case user enter invalid input. However, I am kinda confused about the do while loop works after the failure mode. In this case, I don't have have any condition within while(std::cin.fail()), how did the loop knows if the value is greater than 9 or less than 1 if the user entered a invalid input, since the value is only the condition for the do-while loop to execute! In my case, even if I input a invalid entry, the loop will still ask us to input another number? How does that work? Thank you for your help.

• Hi Winston!

When @std::cin fails to extract, it will set @value to 0. The condition of the while loop includes

which is true when @value=0.

I prefer an approach that doesn't rely on @std::cin behaving like that. This allows us to accept 0 as an input if we ever wanted to.

• Winston Lai

Got it!! Thank you!!

• Tubbs

Any tips and did I follow everything correctly?

• Hi Tubbs!

Your code isn't a solution for any of the quizzes of this lesson. Anyway, suggestions:
* Line 2: Global variables are evil, move @input inside @main.
* Line 2, 15: Use uniform initialization
* Line 11: Don't use 32767, use @std::numeric_limits<std::streamsize>::max()
* Line 17: Missing line feed
* @main Missing return statement

Hi!

Could you please explain what does scores[student] means ? Does it mean that student 1 will be assigned the value of the first element in the array , student 2 will be assigned the value of the second element and so on ?

@scores in an array of @numStudents integers. @student is an integer.
You can access the elements in @scores by writing

The index can be a variable too, in this case, it's @student. The element at index @student is accessed.

But if scores is the array , then could you please explain why you’ve written student[3] when student is not an array ? Shouldn’t it have been scores[3]? I’m sorry if I’m mistaken.

• You're right! There is no "students".

Alright I understood now . Thank you very much for helping 🙂

• firebow

is it true that sizeof returns a unsigned integer
i compared the size of an array with a normal int and it caused a warning

• Hi Firebow!

You can always check the documentation.
The sizeof operator returns an @std::size_t, which is an unsigned int.

References
sizeof - https://en.cppreference.com/w/cpp/language/sizeof
std::size_t - https://en.cppreference.com/w/cpp/types/size_t

• ayush

plzz tell me what is wrong in this

• nascardriver

semicolon in line 33

• Inan

I have read some books before about C and C++ but I gotta your tutorial really sapasses them.Its neatly designed and most of the concepts are covered.As i see till no.Keep doind the good job.

• derbutzemann

Here is my solution for Quiz 2..

• nascardriver

Hi derbutzemann!

* Don't call @std::cin.clear and @std::cin.ignore unless you have to. Out-of-range inputs don't break or mess up the stream.
* Use @std::numeric_limits<std::streamsize>::max() instead of 32767, see the documentation.
* Line 31, 32: Use uniform initialization.

Point 2 and 3 are Alex' code, but even if it's not your code, it's still in your program.

References
* std::istream::ignore - http://www.cplusplus.com/reference/istream/istream/ignore/#parameters

• derbutzemann

Hi nascardriver!

* @std::cin.clear and @std::cin.ignore, I saw it in the old chapter that we have to do them in order to prevent user to put wrong values? What is exactly wrong? Because I simply took one of my old function ( double getDouble() ) and configure it so that it reaches this requirement: "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 an integer value until they do."

* Thanks for this. I will look into it.

* Do you mean something like this?:

* Point 2? Point 3? Sorry I didn't get this?

• nascardriver

Let's say the user enters 18. Extraction is successful and the stream is empty. There's no need to clear the error bit or the stream. You only need to do that when extraction failed (You might need to call @std::cin.ignore, I don't know).

> Do you mean something like this?
That won't work, line 3 tries to declare an already existing variable.

> Sorry I didn't get this?
The second and third things I said (The limits thing and uniform initialization). The affected code was supplied by Alex and not (entirely) written by you.

• derbutzemann

> I have tried many integers but 10 :d I didn't know that 10 is allowed..

> Array worked but I couldn't do const int.. :/

> Well of course I take somethings from Alex' code.. getInteger() for example. This one I have it already from one of the Chapter, I wrote same things again and tried to make a new logic but any other thing is mine in this code. In fact, I was really happy when I saw that I used break in the correct place like Alex :d

Hi,
I am trying to remove spaces from a particular input sentence and print the output sentence wit no spaces. I am not getting any error for my program but it still doesn't print the right output. Code is below. Please help!

• nascardriver

* Don't use 'using namespace'.
* Use uniform initialization.
* Prefer ++prefix over ++postfix (same for --).
* Don't use @system unless you have to.
* Don't use a different iterator name in every loop.
* Don't use variable length arrays, they are not a feature of standard C++.
* All your arrays are short by 1, you need a zero-terminator.

@l is declared inside the loop, it will be set to 0 in every cycle.

Here's a cleaner solution

• Hi Alex!

here is my code but whhy foes the array[iii] do this with the code?

and where is nascardriver?

• nascardriver

Hi Ali!

Don't you worry, I'm still here.

> here is my code but whhy foes the array[iii] do this with the code?
Does what?

• nascardriver

• Hi!
I have been staring at this code for almost 10 minutes now and i still cannot figure out @students is used for. can you explain that to me in details? (also in the braces @[students]?)

is there something wrong with me? or was it hard for you to understand it the first time?

• nascardriver

Hi Ali!

It's a variable like any other. When used in a loop, this variable is usually called i (int) or j (int) or s (size_t) or ui (unsigned int) and so on. You can name it whatever you like.

• Alex

When we want to index an array, we need to provide the numeric value of the element we want to access. For example, scores[0], scores[1], etc...

This array index doesn't need to be a literal number though. It can also be a variable, or any other expression that evaluates to an integer.

In this case, we're using a loop and an incrementing variable to access each element of the array sequentially, and add the value of that array element to totalScore.

• Silviu

In quiz number 3 i tried to change the positions,(so is that what it supposed to do ?)to become the last one in the array or this maxIndex=maxScore and output maxIndex ? I don't think i understood the question very well so hit me with the right choices, so i can look at the solution to escape easy, but i don't want to. Thank you.

• nascardriver

Hi Silviu!

Hint: Replace the @maxScore variable with a maxIndex variable. @maxIndex holds the index of the element with the highest score. You don't need any other variables. You're not supposed to write to the array. The behavior of the program should stay the same.

• Silviu

ok, thank you, the struggle is real ...^^

• Bouke285

I've heard the term const correctness used quite a bit. Should we always strive to mark every function parameter as const if possible?

• nascardriver

Hi Bouke!

If you have no intentions to modify the parameter, mark it const.
This is usually not done for parameters passed by value, because it really doesn't make a difference. Having const parameters will become important from Lesson 7.3 (Passing arguments by reference) onward.

• Will

• nascardriver

Hi Will!
Your code looks good, just a few notes:

Line 7: maxStudent is badly named, it should have "index" in it's name
The for-loop without braces, but braces for the if-statement looks weird

Line 17: You're missing spaces, around the << operator (they don't change anything, but they look better)

• Jay

#include <iostream>
using namespace std;

int main() {

int scores[] = { 84, 92, 76, 81, 56};
const int numStudents = sizeof(scores) / 4;

int maxScore = 0; // keep track of our largest score
int maxIndex(0);

// now look for a larger score
for (int student = 0; student < numStudents; ++student)
if (scores[student] > maxScore)
maxScore = scores[maxIndex = student];

cout << "The best score was " << maxScore << ", " << "array index number: " << maxIndex << endl;

return 0;
}

• nascardriver

Hi Jay!

Please use CODE tags when submitting code

Line 2: Don't use 'using namespace'
Line 7: Use sizeof(scores[0]) or sizeof(int) instead of 4 for cross compiler/platform compatibility.
Line 9,10: Inconsistent use of initializations.
Line 15: Interesting, I like it
Line 17: [...]", " << "ar[...]" could be written as [...]", ar[...]"

Good job

• merocom

• nascardriver

Hi merocom!
Good work, your program does the job. There are some minor issues:

Line 3: Don't use 'using namespace'
Line 15,21: Inconsistent use of ++i and i++
Line 24: index + 1 is incorrect. You'd need index + 1 to name the n-th element, but the index starts at 0.

You could have solved the quiz with one loop and fewer variables, see Solution 3

• david

Hi Alex I tried doing quiz 2 with one for loop with the cost of a new variable I called index but i don't know which way to go in terms of performance

and another question if you please Alex, in the next
loop when I remove the "else" and then test the input with a value that causes std::cin.fail the if condition doesn't get executed and the loop stops although its a an infinite ,why do you think is that?

Alex, we really appreciate the efforts you make, thank you so much for your help.

• Alex

1) If you're unsure what's of multiple options is more performant, you can time each option and compare them. I show how to do that in lesson 8.16.
2) If you remove the else statement, then the second if will evaluate every time -- and that's problematic, because userInput is never initialized, and if you enter an invalid input (non-integer), then userInput will not be given a value from the user. This means the second if statement will be evaluating userInput when it has never had a value set. This will lead to undefined behavior.

• Norbert

Hey!

I have a question for Quiz #2.
We have to insert a number between 1 and 9.
But the Array starts with number 0 and ends with 8.
So whenever I input 1 I'll get the second number (6) as the index, which should be 4!
I tried it with my own code, and copied paste your code, and It happens at both.

The array: { 4, 6, 7, 3, 8, 2, 1, 9, 5 };

Code reacts to the numbers:
The number 1 has index 6
The number 2 has index 5
The number 3 has index 3
The number 4 has index 0
The number 5 has index 8
The number 6 has index 1
The number 7 has index 2
The number 8 has index 4
The number 9 has index 7

A new number appears which is zero.
And 9 is never shown.

(If this is not a problem, but should be the behaviour of the program, I am sorry. I'm still a rookie.)

I just want to know, If this is a problem or not.
If not, I'd like to know why this is happening.

• Alex

This is as desired. The array holds the values 1 through 9 in array indices 0 through 8. Getting used to 0-indexed arrays is definitely a challenge when you're used to counting things starting at 1.

• Ned

I am still learning about programming and I am trying to build a strong foundation.  I do have a question about this line

const int numStudents = sizeof(scores) / sizeof(scores[0]);

What does that accomplish? I am so used to just setting a const int globally but I saw a comment on one of the forums that presented the issue of someone not filling in the entire array.  That would cause the rest of the array to be filled with nonsense.  Is that line made to alleviate this problem?

• Alex

This is a "useful hack" to get the number of elements in a fixed array. sizeof(scores) returns the size (in bytes) of the entire array. sizeof(scores[0]) returns the size of one element of the array. Dividing the two tells you how many elements there are in the array. This works regardless of whether the array is full or not, or initialized or not.

• Ned

Thank you!  Was this a lesson that I overlooked or does things like this come with practice?

• Alex

It was shown in a previous lesson in this chapter. You must have overlooked it.

• Lamont Peterson

Perhaps it's a bit more than most folks are trying to accomplish at this point, but as I'm going through all of these lessons and especially the quizzes, I'm trying to build more complete solutions, incorporating as many of the "best practices" of programming in general, C++ in particular and many / most mentioned in the Lessons (my compliments on many correct best practices advice, too).  Still, I felt it might be helpful to share a couple of thoughts I had and a minor optimization which most people never think of (I've never found any C++ book in over 25 years that would mention this simple min/max search optimization, for example), therefore, I'm sharing the thoughts, here.

I hope they prove useful to others.

I built my solution to #2 using several functions, some of which are actually placed in other files and I include the headers.  Here are the prototypes:

One major reason is to be reusable, but even more useful at this stage of things, it makes the logical progression easier to read and modify if needed.  I've found these to be very useful benefits when developing new code.

Here is my main () function:

You'll note that I've also added error checking and reporting in my findArrayElement () function, which is checked for in main () in case the requested number isn't found.  The commented out version of the array[] initializer has such gaps (namely, -1 and 0).  The NOT_FOUND code is -2, and (of course) I have no problems using such error codes in this example.  The lesson here is, because arrays cannot have less than zero elements, the negative integers for error codes can never conflict.  Whenever one writes code, they should be able to identify and report errors where it's sensible to do so and applying a little logical thinking can make the error reporting robust, too.

Here are the findArrayMax () and findArrayMin () functions:

The findArrayMax () function is easy to understand and the logic of how to start off, using "int max = 0;" as done in the Lessons is also easy logic for beginners.  But, think about what value should you start your "int min = ??" at?  If you start at 0 (zero), but the minimum value in the set is greater than 0, then your code won't work.  Pause a second and go back to finding maximum, and the same problem exists.  Now, if we were working with unsigned integers, we could bound the start of min and the start of max (initial values before starting the array searches) at "int max = 0" and at "int min = 65535" (or other value, depending on the sizeof (int)).  For max, this appears to be easier to figure out than for min, and one could certainly go off and write a "fancy" bit of code to ensure that min starts with the largest possible value for the type in use.  That would be ugly, but I have a better solution.

This very simple code optimization does two things for us, by simply initializing max or min with the value in the first array element (e.g., array[0]); first, we loop one less time, because the first comparison is now between array[0] and array[1], from which min (or max) will now hold the smaller (or larger) of the two, then as we loop, we compare the rest of the array elements against the smaller (or larger) of the first two elements; second, we don't have to care about hardcoding a starting value for comparison, at all, because if the first value is the smallest (or largest) in the array, it works, but if not, it still works.

One less trip through the loop isn't too big of a deal, but it's still technically an optimization.  Not having to bother with figuring out the bounds of the search at all and letting it find the bounds on it's own ... priceless.

TL;DR

Too late, right?

For those who are interested in the rest of my solution's code, here's the complete program in one file:

• Finn St John

Hi alex,

I think i missed this in an earlier lesson, but why, in the increment statement of your for loops do you increment before and not after? is it bad to increment after?

• Alex

Because pre-increment is more performant than post-increment.

In most cases, it probably won't matter (the compiler should optimize this for you).

It's not "bad" to do a post-increment instead of a pre-increment, it's just not quite as good.

• Finn

Thanks, you do a great job with this website. It's much better than any other online C++ tutorial I've tried.

• John Halfyard

The solution to question#2, when executed, accepts the value of "4h".  So it as long as you put an integer between 1-9 then you can put anything after it.  How can this be fixed?

• Alex

Depends on how you want to fix it. Easiest thing to do is do a std::cin.ignore(32767, '\n') after accepting the user input to get rid of any extraneous input (in this case, the 'h').

• Rohit

I wonder if this line:

const int numStudents = sizeof(scores) / sizeof(scores[0]);

is a good candidate for the typedef size_t ? so something like const std::size_t = sizeof(scores) / sizeof(scores[0]);

Since the time I have read about it, I am trying to find a good place to use it. From what I have read, it looks like it's a good candidate for storing the output of sizeof operations..

Can you confirm/deny this usage of size_t

• Alex

size_t is a typedef for an unsigned int (the size of the int isn't specified and may vary). Size the sizeof() operator returns a size_t, and this calculating is the division of two size_t's, it seems like using size_t here would be appropriate.

• Peter B

Hi. May I ask, what do you think about the following code? It’s not really suitable for ongoing usage but if you use the code only once, it produces the same result as your solution for Quiz #2, but only it uses one loop less.

• Alex

You've merged the second and third steps into a single loop, which is totally fine.

• samir sabbah

[/
#include <iostream>

using namespace std;

int num;

bool Invalid()
{
do
{
cout<<"Please enter a number between 1 and 9 : ";
cin>>num;
}while(num < 1 || num > 9);

return false;
}

void printArray()
{
int array[] = { 4, 6, 7, 3, 8, 2, 1, 9, 5 };
int arrayLength = sizeof(array)/sizeof(array[0]);

if(Invalid() == false)
{
for(int count = 0 ; count < arrayLength ; ++count)
{
cout<<array[count]<<" ";
}
cout<<'\n'<<array[num];
}
}

int main()
{
printArray();

}]

is correct if i wrote the code for question 2 like this ??.

• Alex

I'm not sure why invalid returns a result at all, since it always returns false. Similarly, I'm not sure why you're checking if the return value of invalid() is false, since this will always be the case.

• Hi Alex and other commenters,

This was my approach to solving question 2, I thought I would include a check to make sure that the user not only entered a number in range but that it was also an integer, it is a bit of a hacky approach but it seems to work ok, what do you think?

• Alex

"while (value != static_cast(value) ..." definitely seems hacky.

The best way to do this kind of thing is to read in the user's input as a string and then do validation on the string to ensure it's an integer.

• Thank you, I thought that there must have been a better way.

These tutorials are great, thank you for all the hard work you have put into this

• Scott

Hey Alex! Love your tutorials, thank you so much for all your hard work! I just noticed that in your quiz question 1, the question initializes arraylength at 9 and then initializes the array with the length arraylength... however, in the solution, you show the array initialized first and then initialize the arraylength with the array's size divided by an array element size. Was this intentional? Is this answer acceptable?

Oh, and I've also been meaning to ask... when I type array into my codeblocks, it seems to recognize it as an actual C++ term and turns the word green, so I've just been using arra instead. Is it okay to use the word array if it is a green word?

• Alex

Thanks for pointing out the inconsistency between the quiz question and answer. I've updated the quiz question to be in alignment with the answer. Whether the former method (explicitly setting the length) or the current method (deriving the length from the initialized array) is "better" depends on your constraints. If the array length must be 9, then explicitly setting the length to 9 is better because it makes this clear, and enlists the compilers help in enforcing this limit. If the array length can be set to whatever the number of initializing elements is, then it's better to derive the length so there isn't a mismatch between the array length and number of initializers. In this example, I think the latter is likely be less error prone, so it's a better choice.

array isn't a reserved word in C++, so it's fine to use. However, many syntax highlighters do highlight it as a reserved word even though it's not. Visual Studio does because it's a reserved word in C++/CLI. I'm not sure what Code::Blocks' reason is.

• Scott

Thanks so much for your reply! You're a damn saint for helping all of us!