I was always under the impression that a variable declared in any kind of loop statement is scoped to that statement alone. And a little poking around in similar questions seems to confirm this idea. So I am puzzled by the following excerpt from Stroustrup's A Tour of C++ (§4.2.3 Initializing Containers p. 38):
"The push_back() is useful for input of arbitrary numbers of elements. For example:
Vector read(istream& is) {
Vector v;
for (double d; is>>d;) // read floating-point values into d
v.push_back(d); // add d to v
return v;
}
The input loop is terminated by an end-of-file or a formatting error. Until that happens, each number
read is added to the Vector so that at the end, v’s size is the number of elements read. I used a for-statement rather than the more conventional while-statement to keep the scope of d limited to the loop."
This seems to imply that variables declared in the condition of a while statement persist outside the statement body.
Let's examine that loop:
for (double d; is>>d;) // read floating-point values into d
v.push_back(d); // add d to v
Here we have:
a declaration of d
a loop condition
an empty "do on each iteration" expression
And, yes, d is limited in scope to the for loop.
Now try writing a while loop to do the same job, keeping d limited in scope. You won't be able to, because there's no place to put a declaration in the preamble of a while. Only for has that feature. A while only has a condition.
That doesn't mean the scoping rules are different for while; it only means that it is not possible to write this code using while. There aren't any "variables declared in the condition of a while statement".
[..] that variables declared in the condition of a while statement [..]
That's not possible.
Using a for statement allows to declare a variable like this
for(int a = 0; a < 5; a++) {
// Use a
}
// a is not visible anymore
If you use a while loop, it is visible
int a = 0;
while(a < 5) {
// Use a
a++;
}
// a still visible
Related
Our teacher for our introductory C++ course was speaking on the nature of for loops and how everything within the parentheses can be empty as long as the semicolons are there. My question is, if I were to take two for loops, one after the other, that have the same variable involved in their update statements, is it consistent across all compilers that, once the first for loop is exited, the second will just pick up the value of the variable that came about from the first loop if you keep the initial statement of the second loop empty? Our teacher was uncertain as to whether this interaction was compiler-specific; it worked in VS2017, but she expressed doubt as to whether it would work in earlier versions.
If your variable is part of the first for loop:
for(int x = 0; 10 > x; ++x)
{
}
for(; 20 > x; ++x)
{
}
then per the standard 'x' is not even defined for the second loop and the code will not compile. Note that some older compilers don't follow the standard on this point and will behave as in the next example.
If the variable is defined outside the first for loop:
int x = 0;
for(; 10 > x; ++x)
{
}
for(; 20 > x; ++x)
{
}
then when the second loop is entered 'x' will have the value it had at the time the first loop ended. In no case will 'x' be re-initialized by the second loop, or have some otherwise random value. It will either have the value obtained at the end of the first loop or result in a compilation error.
This question already has answers here:
What does it mean when the first "for" parameter is blank?
(8 answers)
Closed 4 years ago.
I'm studying for my exam and I bumped into this example that has a line that says:
for(;i<=m;i++)
The thing I don't understand is why is there a ; with nothing in front of it?
what does it do? What does it mean?
A for statement has the following syntax:
for (declaration; condition; post-condition)
The declaration happens once and once only. The condition is checked at the start of each loop and determines whether the loop will proceed, and the post-condition happens at the end of the loop.
Any and all of these statements can be omitted.
Yours is simply a for loop that does not require a declaration, perhaps because something is already declared, like so:
int i = 0;
for (;i<=m;++i)
If you wanted a loop to run indefinitely, you could omit the second statement:
for (int i = 0; ;++i)
In this regard, infinite loops are typically written as
for (;;)
You may wish to omit the post-condition, perhaps because you're using iterators and change it during the loop
for (auto it = std::begin(v); it != std::end(v);)
what does it do, what does it mean ?
It means that the initializing part of the for-loop is empty, i.e. no loop-variable is initialized in the scope of the loop.
This construct is most common in situations where you want to access the loop variable after the loop is left, e.g. in
int i = 7;
for(; i < 100; ++i) {
if(isPrime(i)) break;
}
assert(i == 11); // can access i now
This means a part of this statement is declared somewhere before.
i=0
for(;i<=m;i++)
This loop says,for every time that i is smaller than m, I'm going to do whatever is in the code block. Whenever i reaches m value, I'll stop. After each iteration of the loop, it increments i by 1 (i++), so that the loop will eventually stop when it meets the i <=m.
The thing that i don't understand is why is there a ";" with nothing in front of it. what does it do, what does it mean.
It is a valid statement that does nothing.
You can have empty statements any where you like. It's quite common to see them in looping constructs.
The i variable must have been initialized somewhere else.. so it picks the value from there and the loop iterates from that value of i.
Below is a code snipped with 3 nested loops. Variables curs and tempv are getting redeclared at each iteration of the outermost for-loop. This should have given me error but I am able to run it successfully without errors on gcc 4.8.4.
for(int i = 0; i<lend; i++)
{
string curs = vstring[digits[i]-'0'];
vector<string> tempv;
for(int j = 0; j<v.size(); j++)
{
for(int k = 0; k<curs.size(); k++)
{
tempv.push_back(v[j] + curs[k]);
}
}
v = tempv;
}
Is it fine to redeclare variables within for-loop? I have an understanding that in C++ a variable cannot be redeclared in the same scope.
Is it fine to redeclare variables within for-loop? I have an understanding that in C++ a variable cannot be redeclared in the same scope.
It's one single lexical scope, where these variables are declared once. The fact that the execution enters it repeatedly is irrelevant - it's not like you get duplicate definition errors for variables that are declared in a function that gets called many times. As always, each time you enter a scope you get a new instantiation of variables defined in it.
In other words: scoping rules are about the static, lexical structure of the program, which is unrelated to how the program flow of execution will actually happen; they act as a blueprint for its runtime behavior, in that they instruct the compiler about how to parse the rest of the block and what code to generate for each time the scope is entered.
” Variables curs and tempv are getting redeclared at each iteration of the outermost for-loop
No, they're getting instantiated at each iteration. Created, and at the end of the block, destroyed. Modulo optimization done by the compiler.
Scopes are a compile time notion. Something you see by inspection of the code. Instantiations are a run-time effect. The same variable declaration can be executed any number of times, instantiating the variable that number of times. Well, except if it's static, in which case it's instantiated once.
” I have an understanding that in C++ a variable cannot be redeclared in the same scope.
It cannot be redeclared directly in the same scope, but it can be redeclared in a nested scope. And you have a number of nested scopes. Let's consider them:
for(int i = 0; i<lend; i++) // ← For loop scope.
{ // ← Block scope.
string curs = vstring[digits[i]-'0'];
vector<string> tempv;
for(int j = 0; j<v.size(); j++) // ← For loop scope.
{ // ← Block scope.
for(int k = 0; k<curs.size(); k++) // ← For loop scope.
{ // ← Block scope.
tempv.push_back(v[j] + curs[k]);
}
}
v = tempv;
}
Formally the for loop is defined by an equivalence to a corresponding while loop placed in an outer block that contains the declaration of the loop variable, if any. However,
C++17 §6.3.3/1:
” Names declared in the init-statement, the for-range-declaration, and in the condition of if, while, for, and
switch statements are local to the if, while, for, or switch statement (including the controlled statement),
and shall not be redeclared in a subsequent condition of that statement nor in the outermost block (or, for
the if statement, any of the outermost blocks) of the controlled statement; see 9.4.
For example, in your code the outer for loop's i cannot be redeclared directly in the block that constitutes that loop's body, even though it's a nested scope, but can be redeclared in the inner nested loop.
This is perfectly legal, and in fact, it is used all the time. Each iteration can be viewed as a brand new scope in this context.
What would be the difference of declaring i at the beginning of the program
int a, b, c, i;
vs in the for loop
for (int i=0;i<=n;i++)?
I developed a habit to declare it in the for loop and I don't know if that's fine (I'm better at JS and I encountered many problem in my programs because of this, but in C++ I didn't.)
Thanks a lot.
It depends.
Most of the time it's OK to use
for (int i = 0; i <= n; i++) { ... }
However, sometimes you want to know the value of i when the loop ended. In that case, you would need to declare the variable before the for loop.
int i = 0;
for ( ; i <= n && (some other tests); i++ ) { ... }
// Do different things based on the value of i.
if ( i == n+1 )
{
dothis();
}
else
{
dothat();
}
This is a scope problem. If you define int a before the loop, you can use it in and outside the loop. When you define it inside the loop you can only use it inside the loop.
Here is a nice article about Scope in the MSDN
ps.: Your loop doesn't work, unless you define and initalize the n variable
It depends. If you don't need i after the loop (the scope will only be the for loop) then declare it in the for loop. If you need it after the loop (the scope is the block of code your in) then you must declare it outside and before the loop.
When int i is declared outside the for loop, it can be accessed outside the for loop and inside but when you define it inside the loop, it can only be used inside the loop. Usualy, if you need it for the for loop define it inside the loop.
I'm coding a simple function using std::vector below where input is an integer vector and the function proceeds the iteration based on the number of elements in the vector.
In terms of space and time efficiency, which following code are suitable?
HugeClass is actually a Big Integer which contains complex arithmetic while I put a simple arithmetic below for simplicity.
1) Gives a dimension of vector
void (HugeClass& huge, std::vector<int>& vec, int dim){
for(int i=0;i<dim;i++){
huge+=vec[i];
}
}
2) Calls a std::vector.size() to iterate
void (HugeClass& huge, std::vector<int>& vec){
for(int i=0;i<vec.size();i++){
huge+=vec[i];
}
}
dim can range in [100,1000000]
The syntax of a for loop in C++ is:
for ( init; condition; increment ) {
statement(s);
}
Here is the flow of control in a for loop:
The init step is executed first, and only once. This step allows you to declare and initialize any loop control variables. You are not required to put a statement here, as long as a semicolon appears.
Next, the condition is evaluated. If it is true, the body of the loop is executed. If it is false, the body of the loop does not execute and flow of control jumps to the next statement just after the for loop.
After the body of the for loop executes, the flow of control jumps back up to the increment statement. This statement allows you to update any loop control variables. This statement can be left blank, as long as a semicolon appears after the condition.
So in the case of
for(int i=0;i<vec.size();i++) {
huge+=vec[i];
}
vec.size() called each time but is probably inlined, and is probably a simple function.
On top of which
A smart enough optimizer may be able to deduce that it is a loop invariant with no side effects and elide it entirely (this is easier if the code is inlined, but may be possible even if it is not if the compiler does global optimization)