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.
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.
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 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
I have a for loop which access many memory pointers in each iteration. For each of these memory pointers, I created an index. My problem is that when I try to use open mp to parallelize this loop, I get the following error:
error: expected iteration declaration or initialization
I thought that this error would be one of the following:
-Open MP does not accept increment different than ++ or --
-Open MP does not accept multiple initialization in a loop
For reasons regarding performance, it is important to me to use these multiple indexes. Does anybody know the answer for my problem?
Here it is the code:
#pragma omp parallel default(shared)
{
int tID = omp_get_thread_num();
int i, iCF, iPF, iNF, iPJG, iCJG, iNJG, iPRJG, iCRJG;
##pragma omp for nowait
for(i=0, iCF=0, iPF=0, iNF=sqrBcksDim, iPJG=0, iCJG=0, iNJG=sqrBcksSize, iPRJG=0, iCRJG=0 ; iCF<RHSArraySize ; iPF=iCF, iCF=iNF, iNF+=sqrBcksDim, iPJG=iCJG, iCJG=iNJG, iNJG+=sqrBcksSize, iPRJG=iCRJG, iCRJG+=rectBcksSize, ++i)
{
}
}
Well, looking at that third clause, you’re doing a lot of inherently sequential computations that depend on the program state at the end of the previous iteration of the loop. You could move all of those operations but the += and ++ updates inside the body of the loop, and from the look of things possibly make the loop condition depend on iNF, correct? But some of them look like they still might be ordered. For a parallel algorithm, are there closed-form initializers you could use inside the loop body that depend only on i or something loop-invariant?
If not, and the inputs to each iteration really do depend on the results of previous iterations of the loop, then it’s not a parallel algorithm
One suggestion:
Here’s how I would try to fix this. You can only initialize i and increment it by a constant within the loop; however, you can equivalently move all the rest of those operations inside the loop. For example, I don’t know what else goes on inside the loop body, but if iCF is initialized to 0, iNF to sqrBcksDim and at the end of each iteration, iCF is set to the previous value of iNF and iNF is incremented by sqrBcksDim, it looks like you could rewrite the loop into something like:
int i;
#pragma omp for nowait
for ( i=0; i < RHSArraySize/sqrBcksDim; ++i )
{
const int iCF = i*sqrBcksDim;
const int iNF = iCF + sqrBcksDim;
// ...
}
Can you do that for your other variables? If you really have a parallel algorithm here, you should be able to, because each run of the loop should only depend on i and loop invariants, which you can use in your initializers. You’ll need to declare a variable outside the loop if you’re going to refer to it outside the body of the loop, but for the time being, just declare a new local variable and don’t read any variable outside the loop that you also write to inside the loop. If there are no implicit sequential dependencies, you should be able to initialize them all at the start of the loop body.
You might not end up doing it that way, but it might help you think about how to refactor.