Consider this snippet of a C program:
for(int i = 0; i < 5; i++)
{
int i = 10; // <- Note the local variable
printf("%d", i);
}
It compiles without any error and, when executed, it gives the following output:
1010101010
But if I write a similar loop in C++:
for(int i = 0; i < 5; i++)
{
int i = 10;
std::cout << i;
}
The compilation fails with this error:
prog.cc:7:13: error: redeclaration of 'int i'
int i = 10;
^
prog.cc:5:13: note: 'int i' previously declared here
for(int i = 0; i < 5; i++)
^
Why is this happening?
This is because C and C++ languages have different rules about re-declaring variables in a scope nested in a for loop:
C++ puts i in the scope of loop's body, so the second int i = 10 is a redeclaration, which is prohibited
C allows redeclaration in a scope within a for loop; innermost variable "wins"
Here is a demo of a running C program, and a C++ program failing to compile.
Opening a nested scope inside the body fixes the compile error (demo):
for (int i =0 ; i != 5 ; i++) {
{
int i = 10;
cout << i << endl;
}
}
Now i in the for header and int i = 10 are in different scopes, so the program is allowed to run.
Unlike C, C++ has the rule,
C++11-§6.5.3/1:
The for statement
for ( for-init-statement conditionopt ; expressionopt ) statement
is equivalent to
{
for-init-statement
while ( condition ) {
statement
expression ;
}
}
except that names declared in the for-init-statement are in the same declarative-region as those declared in the condition [...]
This means that the scope of the for-init-statement and the statement are the same* and the code below will cause error
for(int i = 0; i < 5; i++){
int i = 10; // Invalid.
// ...
}
In C,
C11-§6.8.5/5:
An iteration statement is a block whose scope is a strict subset of the scope of its enclosing block. The loop body is also a block whose scope is a strict subset of the scope of the iteration statement.
Therefore, statement has it's own scope and the above code is valid and equivalent to
for(int i = 0; i < 5; i++){
{
int i = 10; // Valid.
// ...
}
}
Suggested reading: n3337: 6.5.1 The while statement/p(2). Same reference can be found in c++17 draft (n4659) in section § 9.5.1 and §9.5.3 .
It's not redeclaration.
See this carefully...
for(int i = 0; i < 7; i++)
{
printf("i = %d\n", i);
int i = 5;
printf("new i = %d\n", i);
}
Output of the above code:-
i = 0
new i = 5
i = 1
new i = 5
i = 2
new i = 5
i = 3
new i = 5
i = 4
new i = 5
i = 5
new i = 5
i = 6
new i = 5
Clearly, there are two different i's
The newer i has a more local scope.
Is it a bug?
No
What is the purpose?
If it wasn't allowed, it might be very hard to maintain large projects, as you would constantly run into naming collisions.
Generally though, it is considered very poor practice to give the same name to different variables in different scopes, you should avoid doing that whenever possible.
Why is there no warning message?
Use gcc file_name.c -Wshadow to compile.
EDIT: You can also locally lock the originally declared variables by redeclaring them in for loops.
Related
I understand that {...} introduces a new scope, which is why the following would not work:
for(int i = 0; i < 10; i++) {
// Do something...
}
cout << i << endl; // Error: i is not defined in this scope
However, I'm getting the same error when I try the same thing without braces.
for (int i = 0; i < 10; i++) continue;
cout << i << endl; // Same error, not sure why
I expected i to be defined in the 2nd example, because there are no {...} to introduce a new scope.
Any control structure (if, for, while, etc.) without braces applies only to the next statement. The second example is equivalent to the following:
for (int i = 0; i < 10; i++) {
continue;
}
cout << i << endl;
Note that it's often considered bad style to have control structures without braces, because people can forget to add the braces if they add another line, and it can lead to the dangling else problem.
The scope for the visibility of i is the for() loops body.
for (int i = 0; i < 10; i++) continue;
is just equivalent to
for (int i = 0; i < 10; i++) { continue; }
If the braces are omitted, the body is just the statement following the for() loop header.
Consider the following piece of code:
int main() {
int a = 0;
int b = 1;
for (int i = 0; i < 3; i++) {
a = 2;
int c = 1;
int d = 3;
d = a + c;
}
a = b+2;
}
In the piece of code above three variables have a lifespan contained in the body of the loop (i, c and d). I would like to be able to count the variables whose lifespan exists in the body of any given loop using LLVM (i.e. for this loop, my code should return 3).
I found the Live Variables Analysis, but I'm having trouble using it to find what I described above.
Maybe this should just be a comment, but I couldn't express the code inline:
Only two variables have duration within the loop body. i is declared before the loop starts, and lasts until after the last execution of the loop body. In other words, c and d are constructed/destructed 3 times; after the third time they are destructed, then i is.
Thus, the for loop you wrote is equivalent to:
{
int i = 0;
while (i < 3)
{
a = 2;
int c = 1;
int d = 3;
d = a + c;
}
i++;
}
The extra set of braces invokes block scoping; i goes out of scope and is destroyed outside of the for loop body, but before any subsequent code.
int main() {
int T;
cin>>T;
for(int i = 0 ; i < T ; ++i) {
cin>>a[i];
}
/*error:prog.cpp:41:6: error: name lookup of 'i' changed for ISO 'for' scoping [-fpermissive]*/
for(i = 0 ; i < T ; ++i) {
cout<<Z(a[i])<<'\n';
}
return 0;
}
When I add int before i in the second for loop, the code runs perfectly.
NOTE: a[] and Z() are defined before main().
I am new to GCC 4.9.2 . I have used Turbo C++ till now.
A long time ago in C++ your code was legal. An identifier like i declared in a for loop was still visible after the loop.
That changed, and by the time C++ was standardised in 1998 the scope of a variable declared in a for loop was just the body of the loop.
Your code is designed to work with the old system, and the compiler is telling you that that is no longer allowed.
Replace for (i = with (for int i = in the second loop and you're done. (And now you have two different variables called i rather than one.)
The declaration if i only exists in the scope of the for loop. Once it exits, you lose the i declaration and cannot reuse it unless you re-declare it in subsequent loops.
for(int i = 0 ; i < T ; ++i) {
cin>>a[i];
} // scope of i ends here
for(i = 0 ; i < T ; ++i) { // loop has no idea what i is now
cout<<Z(a[i])<<'\n';
}
i'm using visual studio 2010 and when i do something like
for(int i = 0, j = 0; i < 10; i++)
{
if(m_Var == 1)
j++;
}
if(j == 0)//This line errors undeclared identifier
DoSomething();
I have declared j in the for loop so why is it erroring "undeclared identifier"?
another example would be
for(int i = 0; i < 10; i++)
{
m_Var1++;
}
for(i = 0; i < 200; i++)//This line errors undeclared identifier
{
m_Var2++;
}
that code errors even though it is declared in the for loop, but why? is there a way to do this without having to declare i BEFORE the loop but declare it within the loop instead like in the above examples?
In the first example, j only exists in the scope of the loop
for(int i = 0, j = 0; i < 10; i++)
{
if(m_Var == 1) j++;
} // i, j exist no longer
In the second example, the same applies to i. It's scope is the first loop. You can even check it without a loop:
{
int i = 0;
} // end of scope, end of i
i++; // error,
As I recall, some very early versions of C++ had variables defined in for loops scoped to the block containing the loop. In modern C++, the scope is restricted to the for loop itself. For example:
void foo() {
for (int i = 0; i < N; i ++) {
// i is visible here
}
// In very old C++, i is visible here.
// In modern C++, i is not visible here.
}
Visual Studio actually has an option to enable the old behavior; you can turn off "Force Conformance in For Loop Scope", under Configuration Properties --> C/C++ --> Language. The corresponding compiler command-line option is /Zc:forScope-. But unless you specifically need this to compile old code that you can't afford to fix, I strongly recommend leaving it with the default setting, which conforms to the modern C++ rule. If you're writing new code, just follow the modern C++ rule. If you need a variable to be visible outside the loop, then declare it outside the loop.
Because you declare it in the loop so once the loop has finished, your j variable is out of scope. When you declare variables inside the for statement like this
for(int i = 0, j = 0; i < 10; i++)
the variable only has loop scope.
I have declared j in the for loop ...
Yes, you have. And you can only use it in that for loop, because its scope ends at the closing brace of that loop. You cannot use it after that.
If you want to use it afterwards, you must move the scope out a little bit, but not so far that it will affect other stuff (localisation is still a good thing). One method is to use block scope, something like:
{
int i, j; // Scope starts here,
for (i = 0, j = 0; i < 10; i++)
if (m_Var == 1)
j++;
if (j == 0) // still exists here,
DoSomething();
} // and ends here.
This still limits i and j to a specific, small area, but allows j to "escape" from the if statement.
c++ uses block scope for that variable - msdn docs
The error is:
In function ‘int returnShortestWeightedBranch(std::vector<route, std::allocator<route> >*)’:
error: name lookup of ‘jj’ changed for ISO ‘for’ scoping
note: (if you use ‘-fpermissive’ G++ will accept your code)
The code is:
for (int i = 0; i< routeVector.size(); i++)
{
if (routeVector[i].exitPoint == exitPointDetailsVector[preserveL].exitPoint)
{
cout << "\n-----------parent: " << routeVector[i].exitPoint;
branch obj;
obj.connectedExitPoint = exitPointDetailsVector[preserveI].exitPoint;
routeVector[i].selectedBranchesVector.push_back (obj);
for (int jj = 0; jj < routeVector[i].selectedBranchesVector.size(); jj++);
{
cout << "\n-----------branch: " << routeVector[i].selectedBranchesVector[jj].connectedExitPoint;
}
}
}
What can be the problem here?
EDIT 1:
I changed the following:
for (int jj = 0; jj < routeVector[i].selectedBranchesVector.size(); jj++);
to:
int jj;
for (jj = 0; jj < routeVector[i].selectedBranchesVector.size(); jj++);
and now it is working!! I fail to understand the REASONS.
You have a semicolon at the end of the inner for statement. That ends the scope of jj there, so it is not visible inside the block.
Edit
You have solved the scope problem, but still have your for loop executing just
<nothing>;
Remove the semicolon after the parenthesis!
for (int jj = 0; jj < routeVector[i].selectedBranchesVector.size(); jj++);
This line ends with a semicolon! It shouldn't :)
Some compilers may not accept the use of the variable 'jj' after the for loop is ended. Since the variable is declared inside the for loop, it is destroyed right after it is executed. Thus when you declare your iteration variable outside the for loop it remains there for further use.
In reality it doesn't work like that and that's why you can force the compiler to ignore the error by adding '-fpermissive'.
False: for(...;...;...;);
True: for(...;...;...;)
You shouldn't use a semicolon, ;