By far, the most utilized loop statement in C++ is the for statement
. The for statement (also called a for loop) is preferred when we have an obvious loop variable because it lets us easily and concisely define, initialize, test, and change the value of loop variables.
As of C++11, there are two different kinds of for loops
. We’ll cover the classic for statement
in this lesson, and the newer range-based for statement
in a future lesson (9.19 -- For-each loops) once we’ve covered some other prerequisite topics, such as arrays and iterators.
The for statement
looks pretty simple in abstract:
for (init-statement; condition; end-expression) statement
The easiest way to initially understand how a for statement
works is to convert it into an equivalent while statement
:
{ // note the block here init-statement; // used to define variables used in the loop while (condition) { statement; end-expression; // used to modify the loop variable prior to reassessment of the condition } } // variables defined inside the loop go out of scope here
Evaluation of for statements
A for statement
is evaluated in 3 parts:
First, the init-statement is executed. This only happens once when the loop is initiated. The init-statement is typically used for variable definition and initialization. These variables have “loop scope”, which really just is a form of block scope where these variables exist from the point of definition through the end of the loop statement. In our while-loop equivalent, you can see that the init-statement is inside a block that contains the loop, so the variables defined in the init-statement go out of scope when the block containing the loop ends.
Second, for each loop iteration, the condition is evaluated. If this evaluates to true, the statement is executed. If this evaluates to false, the loop terminates and execution continues with the next statement beyond the loop.
Finally, after the statement is executed, the end-expression is evaluated. Typically, this expression is used to increment or decrement the loop variables defined in the init-statement. After the end-expression has been evaluated, execution returns to the second step (and the condition is evaluated again).
Let’s take a look at a sample for loop and discuss how it works:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int count{ 1 }; count <= 10; ++count) std::cout << count << ' '; return 0; } |
First, we declare a loop variable named count
, and initialize it with the value 1
.
Second, count <= 10
is evaluated, and since count is 1
, this evaluates to true
. Consequently, the statement executes, which prints 1
and a space.
Finally, ++count
is evaluated, which increments count
to 2
. Then the loop goes back to the second step.
Now, count <= 10
is evaluated again. Since count
has value 2
, this evaluates true
, so the loop iterates again. The statement prints 2
and a space, and count is incremented to 3
. The loop continues to iterate until eventually count
is incremented to 11
, at which point count <= 10
evaluates to false
, and the loop exits.
Consequently, this program prints the result:
1 2 3 4 5 6 7 8 9 10
For the sake of example, let's convert the above for loop
into an equivalent while loop
:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int main() { { // the block here ensures block scope for count int count{ 1 }; // our init-statement while (count <= 10) // our condition { std::cout << count << ' '; // our statement ++count; // our end-expression } } } |
That doesn't look so bad, does it? Note that the outer braces are necessary here, because count
goes out of scope when the loop ends.
For loops
can be hard for new programmers to read -- however, experienced programmers love them because they are a very compact way to do loops with a counter, with all of the necessary information about the loop variables, loop conditions, and loop count modifiers are all presented up front. This helps reduce errors.
More for loop examples
Here's an example of a function that uses a for loop
to calculate integer exponents:
1 2 3 4 5 6 7 8 9 10 |
// returns the value base ^ exponent -- watch out for overflow! int pow(int base, int exponent) { int total{ 1 }; for (int count{ 0 }; count < exponent; ++count) total *= base; return total; } |
This function returns the value base^exponent (base to the exponent power).
This is a straightforward incrementing for loop
, with count
looping from 0
up to (but excluding) exponent
.
If exponent is 0, the for loop
will execute 0 times, and the function will return 1.
If exponent is 1, the for loop
will execute 1 time, and the function will return 1 * base.
If exponent is 2, the for loop
will execute 2 times, and the function will return 1 * base * base.
Although most for loops
increment the loop variable by 1, we can decrement it as well:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int count{ 9 }; count >= 0; --count) std::cout << count << ' '; return 0; } |
This prints the result:
9 8 7 6 5 4 3 2 1 0
Alternately, we can change the value of our loop variable by more than 1 with each iteration:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int count{ 9 }; count >= 0; count -= 2) std::cout << count << ' '; return 0; } |
This prints the result:
9 7 5 3 1
Off-by-one errors
One of the biggest problems that new programmers have with for loops
(and other loops that utilize counters) are off-by-one errors
. Off-by-one errors occur when the loop iterates one too many or one too few times to produce the desired result.
Here's an example:
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <iostream> int main() { // oops, we used operator< instead of operator<= for (unsigned int count{ 1 }; count < 5; ++count) { std::cout << count << ' '; } return 0; } |
This program is supposed to print 1 2 3 4 5
, but it only prints 1 2 3 4
because we used the wrong relational operator.
Although the most common cause for these errors is using the wrong relational operator, they can sometimes occur by using pre-increment or pre-decrement instead of post-increment or post-decrement, or vice-versa.
Omitted expressions
It is possible to write for loops that omit any or all of the statements or expressions. For example, in the following example, we'll omit the init-statement and end-expression, leaving only the condition:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <iostream> int main() { int count{ 0 }; for ( ; count < 10; ) // no init-statement or end-expression { std::cout << count << ' '; ++count; } return 0; } |
This for loop produces the result:
0 1 2 3 4 5 6 7 8 9
Rather than having the for loop do the initialization and incrementing, we've done it manually. We have done so purely for academic purposes in this example, but there are cases where not declaring a loop variable (because you already have one) or not incrementing it in the end-expression (because you're incrementing it some other way) is desired.
Although you do not see it very often, it is worth noting that the following example produces an infinite loop:
1 2 |
for (;;) statement; |
The above example is equivalent to:
1 2 |
while (true) statement; |
This might be a little unexpected, as you'd probably expect an omitted condition-expression to be treated as false
. However, the C++ standard explicitly (and inconsistently) defines that an omitted condition-expression in a for loop should be treated as true
.
We recommend avoiding this form of the for loop altogether and using while(true)
instead.
For loops with multiple counters
Although for loops
typically iterate over only one variable, sometimes for loops
need to work with multiple variables. To assist with this, the programmer can define multiple variables in the init-statement, and can make use of the comma operator to change the value of multiple variables in the end-expression:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { for (int x{ 0 }, y{ 9 }; x < 10; ++x, --y) std::cout << x << ' ' << y << '\n'; return 0; } |
This loop defines and initializes two new variables: x
and y
. It iterates x
over the range 0
to 9
, and after each iteration x
is incremented and y
is decremented.
This program produces the result:
0 9 1 8 2 7 3 6 4 5 5 4 6 3 7 2 8 1 9 0
This is about the only place in C++ where defining multiple variables in the same statement, and use of the comma operator is considered an acceptable practice.
Best practice
Defining multiple variables (in the init-statement) and using the comma operator (in the end-expression) is acceptable inside a for statement
.
Nested for loops
Like other types of loops, for loops
can be nested inside other loops. In the following example, we're nesting a for loop
inside another for loop
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <iostream> int main() { for (char c{ 'a' }; c <= 'e'; ++c) // outer loop on letters { std::cout << c; // print our letter first for (int i{ 0 }; i < 3; ++i) // inner loop on all numbers std::cout << i; std::cout << '\n'; } return 0; } |
For each iteration of the outer loop, the inner loop runs in its entirety. Consequently, the output is:
a012 b012 c012 d012 e012
Here's some more detail on what's happening here. The outer loop runs first, and char c
is initialized to 'a'
. Then c <= 'e'
is evaluated, which is true
, so the loop body executes. Since c
is set to 'a'
, this first prints a
. Next the inner loop executes entirely (which prints 0
, 1
, and 2
). Then a newline is printed. Now the outer loop body is finished, so the outer loop returns to the top, c
is incremented to 'b'
, and the loop condition is re-evaluated. Since the loop condition is still true
the next iteration of the outer loop begins. This prints b012\n
. And so on.
Conclusion
For statements
are the most commonly used loop in the C++ language. Even though its syntax is typically a bit confusing to new programmers, you will see for loops
so often that you will understand them in no time at all!
For statements
excel when you have a counter variable. If you do not have a counter, a while statement
is probably a better choice.
Best practice
Prefer for loops
over while loops
when there is an obvious loop variable.
Prefer while loops
over for loops
when there is no obvious loop variable.
Quiz time
Question #2
Write a function named sumTo() that takes an integer parameter named value, and returns the sum of all the numbers from 1 to value.
For example, sumTo(5) should return 15, which is 1 + 2 + 3 + 4 + 5.
Hint: Use a non-loop variable to accumulate the sum as you iterate from 1 to the input value, much like the pow() example above uses the total variable to accumulate the return value each iteration.
Question #3
What's wrong with the following for loop?
1 2 3 |
// Print all numbers from 9 to 0 for (unsigned int count{ 9 }; count >= 0; --count) std::cout << count << ' '; |
![]() |
![]() |
![]() |
#include <iostream>
int sumTo(int value)
{
int x{ 1 };
for (int y{ 2 }; y <= value; ++y)
{
x += y;
}
return x;
}
int main()
{
std::cout << sumTo(5);
return 0;
}
is this program ok? question 2 solve
"Although the most common cause for these errors is using the wrong relational operator, they can sometimes occur by using pre-increment or pre-decrement instead of post-increment or post-decrement, or vice-versa."
Here you say that the off by one errors can also happen due to pre or post increment/decrement but aren't the end-expressions evaluated as separate statements like you showed in the conversion from for to the while loop? so basically
evaluate as
And since we are not assigning the return value from the "++count" statement to any variable or outputting it to the console, it should be evaluated the same way as "count++" as at the end of statement we i.e. for the next time the condition is evaluated we would still be getting count+1 value for count. As they say stand alone pre or post increment statements are basically the same thing. So this shouldn't really affect the loop. Please correct me if I'm wrong.
Thanks.
Hello Sahil,
please see Waldo Lemmer's question and my reply here https://www.learncpp.com/cpp-tutorial/for-statements/comment-page-4/#comment-489087
Thanks, this clears it.
// Question 2
Thanks for all the great tutorials. It's really helping to make my code better and I'm getting much quicker at it as well now that I practise regularly.
My main problem currently is that I do not always read/interpret the question correctly which makes the problem harder than it needs to be.
I ended up with the following code for question 2.
I'm proud of myself for getting it right first time without compile errors but
I should start practising to also write testcases so that I don't have to go through them manually.
Is there anything else I could improve on the code?
I print the first '1' separately, when I put it in the loop I end up with a '+' at the end where the '=' should be unless I include an if statement in the loop. That doesn't seem effective because then it needs to check that statement every time the loop goes round which is less performant.
# Evaluation of for statements
For the sake of example, ... --> this while loop prints
0 1 2 3 4 5 6 7 8 9 10
Shouldn't it be int count{ 1 }; instead of int count{ 0 };
to get the same result as the above for-loop?
Thanks for the great lesson!
Section "Evaluation of for statements":
- Second paragraph:
> These variables have “loop scope”, which really just a form of block scope where these variables exist from the point of definition through the end of the loop statement.
"which" should be followed by "is".
- Last paragraph:
> they are a very compact way to do loops with a counter, with all of the necessary information about the loop variables, loop conditions, and loop count modifiers are all presented up front.
This sounds weird, I think you should remove "are all".
Section "Off-by-one errors":
- Line 6 of the code snippet:
List initialization should be used.
> they can sometimes occur by using pre-increment or pre-decrement instead of post-increment or post-decrement, or vice-versa
Could you please provide such an example? I can't think of a case where this would be possible.
Section "Omitted expressions", after the console output:
> but there are cases where not declaring a loop variable (because you already have one) or not incrementing it in the end-expression (because you're incrementing it some other way) are desired.
The last "are" should be "is", I think this is called a gerund.
Question #3's solution:
for-ever should b-
Dammit, you got me
Thanks for pointing out all the mistakes! I don't think the second one is wrong, let's see what Alex thinks.
> Could you please provide such an example?
loop a: 1
loop a: 2
loop a: 3
loop a: 4
loop b: 1
loop b: 2
loop b: 3
loop b: 4
loop b: 5
That makes sense, thanks! I don't think it'll be an issue in for loops, though (since the `end-expression` doesn't contain a comparison), so I'll stick to pre-incrementing and pre-decrementing there.
Lucas, the point is the build the critical problem solving abilities with the default language libraries. It would be virtually impossible to cover every industry-specific library out there. You should continue through this entire book and enjoy the experience, then take your newly founded critical thinking/problem solving abilities and apply it to industry-specific libraries. For example, I want to eventually understand how to use the JUCE library for pro-audio VST development. Or the Unreal Engine Library (which is already easy to understand with graphical blue print programing).
Is this acceptable for Quiz 2?
[code]
#include <iostream>
//Wrote 2 ways, the iterative method and the equation method
int sumTo(int value)
{
int i = 0;
int j = 0;
int k = value;
for (i; i < value; i++)
{
j = j + k;
--k;
//std::cout << j << '\n';
}
return j;
}
// Basic equation is n(n+1)/2
int sumEqn(int value)
{
return (value * value + value) / 2;
}
int main()
{
//Named input_value so users naturally associated it with "value" somewhere
//Yet, the naming is significantly different from "value" to prevent "Ad ad" confusion
//The part after input_ can be changed to create natural link to different functions
//E.g. input_number, input_value, input_char.
int input_value;
std::cin >> input_value;
std::cout<< sumTo(input_value)<<'\n';
std::cout<< sumEqn(input_value) << '\n';
return 0;
}
[\code]
- Initialize variables with list initialization for higher type-safety
- `i` isn't used outside of the loop. Define it in the init-statement of the for-loop to reduce its scope.
- `k` is always `(value - i)`, you don't need `k`.
- Use ++prefix unless you need the result. postfix++ is slower.
- Name variables descriptively, avoid abbreviations. Time you save writing is time wasted reading.
- `j += k` is faster than `j = j + k` for non-fundamental types.
Thank you.
I apologise for the late replies.
I think your emails get caught up in the midst of other emails.
I can't edit my comments anymore but I can edit the code.
Please don't update your comments after someone pointed out improvements. Mistakes serve as a good reference for other readers.
I will leave them there for others to refer to.
I believe there will be others who face my issues and it will resurface thousands of times.
Hi,
the for-loop seems to be a very interesting thing. Where can I read in depth about them, with more examples and uses? specifically, I want to know more about what other kinds of end expressions can be used in for loops, other than increment and decrement(and other arithmetic operators)?
I've played a bit with for loop end-expression statement-
The end-expression has to be and expression. `if` and `return` are statements, not expressions. The conditional operator is an expression (It produces a value).
Hi! Great site guys - super helpful and fantastic of you to put in all the effort.
I've run into something that's probably going to make me slap my forehead: I can't understand why this function returns 1...
it seems pr goes to 0.000 once the calculation is performed.
I found that if I
it works. I thought that the compiler would cast the int as double since the result is already declared as a double.
Please place the "Rule: Test your loops with known inputs that cause it to iterate 0, 1, and 2 times." line in a beautiful Rule box.
The given answer for question #2 does not work. I'm pretty sure it's because instead of looping, it moves straight to the return statement to complete the function. Shouldn't there be an if statement there?
Nevermind. I was using curly braces for the for loop.
Moving right along. Thanks. Cheers.
My notes to your previous submission apply. Additionally,
If you don't know what's wrong with these, let me know and I'll tell you.
for (int i{n}; i < m; ++i)
{
doSomething();
}
where n & m are real numbers.
I understand the initialization of i, "i{0};" as I reviewed chap. 1 on, int initialization.
I understand the difference between i++ (use, then increment) and ++i (increment, then use).
Is there a difference in a for loop? Almost all that I see in other places is: for (int i = 0; i < num; i++)
So I get the: for (int i{0}; i < num; ) but was just wondering if it's better or considered better to use
for (; ; ++i) and what, if any, is the difference. Thanks for the help.
I read your other info on the static int var = someNumber. I coded some examples and totally saw how a static doesn't reset, and if called from another function could cause quite a problem if the other function expects var to be zero, thanks for that. Take care.
You explained the difference between `++i` and `i++` correctly.
To make the downside of `i++` more obvious, let's say `i` is an image type and using `++` on it increases the brightness. Let's also say the image is 1GiB in size.
`++i` increases the brightness of `i`, then returns `i`, simple.
But what does `i++` do? It also increases the brightness, but it can't return `i`. It has to return the old value of `i`. There are 2 ways it can accomplish this. Either copy create a copy of `i`, called `temp`, then increase `i` and return `temp`. Or increase `i`, then create a copy of `i` called `temp`, decrease `temp` and return `temp`. Either way, it has to create a copy. The allocation of the memory is expensive, you'll use more ram, and the creation of the copy is expensive. `++i` doesn't need any of this.
The same applies to any other type, just that the effect isn't as noticeable.
The only time you should use `i++` is if you need the old value of `i`. In your loop, you're not using the returned value at all, so there's no reason to use `i++`.
"First, we declare a loop variable named count, and assign it the value 0."
Shouldn't it be " First, we declare a loop variable named count, and initialize it with value 0."?
Yes, thanks!
is it preferable assigning a value or initializing variables in a for loop? and is it good practice to declare multiple variables in a for loop when it's needed?
How would you loop over the characters of a string (std::string) ?
I've found lots of ways but i would want to know which are better or which you prefer and why.
Thanks <3.
Use a ranged-for (for-each) loop:
Good sheet
Quiz 1
Quiz 2
Regarding question 2:
My editor - Visual studio - complains that my return variable does not match the function type. As far as I can see, everything is int.
Does anyone have an idea about why?
There's nothing wrong with your code and I can't reproduce the issue. I suppose you didn't save or you're compiling a different file.
Hello Nascardriver
Thank you for the answer.
I had saved the file, and don't think I was compiling anything else.
Anyways, I changed the language standard from standard to explicitly be C++17 (which I though I allready had done) and the Visual studio complaint disappeared. This does not make sense to me, but if anyone else gets this problem, maybe I found a fix..
Best regards,
Simon
You didn't use any features newer than C++11 in your code. If VS defaulted to C++98 or C++03, this could explain the error.
I noticed something, that the init-statement in the for loop can be initialized to 0 and 1 and would still give you the same result.
for example:
and
will both print out 15
Yes, because
Initializing `num` to 0 adds once extra cycle to the loop that doesn't do anything.
Assignment #1:
Assignment #2:
Assignment #3:
I am Brazilian, and learncpp is an extremely sensational site (even if it only supports your default language). I'm learning a lot from you, thank you.
I'm starting to feel that Learncpp.com hates unsigned haha :(
Unsigned is good when used with care. But it's easy to mess up, so we show what not to do.
My approach:
Assignment #1:
Assignment #2:
Assignment #3:
Thank you!
Looking good :)
Quiz 3 is unrelated to endianness. The language defines that `count` has to wrap around to it's maximum value, no matter how the integer is stored. You solutions to the problem however is correct, using a `signed` integer stops the loop.
Here is my answer to question 1, I really need to figure out how the modulo operator works. I was printing odd numbers at first
Have a look at the quiz's solution and make sure you understand it, you don't need the modules in this quiz.
Modulus returns the remainder of a division, so you can check if it's 0 to print even numbers
Here is my code for Quiz question 2).
Is it considered a good or bad idea to name the input/variables from one function to another with the same name when they reference the same thing?
#include <iostream>
int getNumber()
{
std::cout << "Input an integer you wish to sum to: ";
int value{};
std::cin >> value;
return value;
}
int calcSum(int value)
{
int total{};
for (int count{ 1 }; count <= value; ++count)
total += count;
return total;
}
void printTotal (int value , int total)
{
std::cout << "The sum of the number from 1 to " << value << " is " << total << "." << '\n';
}
int main()
{
int value{ getNumber() };
int total{ calcSum( value) };
printTotal( value , total );
return 0;
}
Please use code tags when posting code.
If two variables mean the same thing, they should have the same name. There are exceptions when a variable's name is affected by its context.
Under "multiple declarations" my compiler keep showing this error if i use uniform initialization like in the example.
error C2064: term does not evaluate to a function taking 1 arguments
error C2064: term does not evaluate to a function taking 1 arguments
I use VS2019. It compiles only if i use uniform or copy initialization like this,
_________________________________________________________________________________________
That was an error in the lesson, thanks for bringing it to our attention!
`iii` and `jjj` already existed, so they can't be initialized anymore. We need to assign a value instead.