visual undeclared identifiers? - c++

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

Related

Having to redeclare an int for a second for loop

I am playing around on edabit.com C++ challenges to refresh myself and I was presented with a challenge where I needed to write a function that would, given a vector, return true if all even indices are even and all odd indices are odd. Otherwise return false. The logic and everything of the function was fine. I know there's a few ways to do this but came up with a (I think) creative solution where instead of running through one for loop with a check if the index is odd or even, I instead wrote two subsequent for loops that increment by two each. One starting at 0 and the other starting at 1. Once it finds a mismatch it returns false. Otherwise at the end it will return true. I am coming from JavaScript where you would not need to redeclare the index variable (if using var not let) but this code failed to compile:
bool isSpecialArray(std::vector<int> arr) {
for(int i = 0; i < arr.size(); i = i + 2){
if(arr[i] % 2 == 1){
return false;
}
}
for(i = 1; i < arr.size(); i = i + 2){
if(arr[i] % 2 == 0){
return false;
}
}
return true;
}
Stating:
error: use of undeclared identifier 'i'
for(i = 1; i < arr.size(); i = i + 2){
^
And of course declaring int in the second for loop cleared the error and the program executed as expected. I'm guessing this is due to garbage collection, but is there a specific rule in the standard that defines this? Or is this maybe a per compiler thing? My understanding of the garbage collection was that the variable once declared is not cleared from memory until is no longer being used in the current function it is defined in. Is this different due to the scope of the for loop, similar to JavaScript's let?
Firstly, JS and C++ have very different models of scopes, and JS is known (sorry) for its bad practices. In C++ the rule is more consistent: the variable is destroyed whenever the program exits the scope. That means that in this code:
for (int i = 0; ; ) {
}
the variable i is defined just for this scope, it cannot be reused in another (not nested) loop, is not seen elsewhere, and the name can be reused or redefined in the inner scopes. This gives you the advantage that it is much easier to control the data flaw and to have less side effects. So the solution for you is to declare another variable i in the second loop:
for(int i = 1; i < arr.size(); i = i + 2){
if(arr[i] % 2 == 0){
return false;
}
}
As long as you are from the JS world I would give you more recommendations. First, do not pass the vector by value (unless you realize what you are doing). Pass it by reference or even better by const reference:
bool isSpecialArray(const std::vector<int> &arr) {
// ...
}
Next, a potentially more efficient and more idiomatic way to increase the index is i += 2.
And the final observation: there is no "creativity" in your solution, but there are drawbacks. This code becomes less cache friendly, and this may be considered as a bad practice.
There is no garbage collection in C++, and even if there were, it wouldn't explain your error. The actual cause is simple: variables declared as part of a for loop go out of scope after the loop.
variable i in your program was declared inside a block or curly braces ({ }). So, variable i is a local variable which can be used only inside that block.
bool isSpecialArray(std::vector<int> arr) {
int i;
for(i = 0; i < arr.size(); i = i + 2){
if(arr[i] % 2 == 1){
return false;
}
}
for(i = 1; i < arr.size(); i = i + 2){
if(arr[i] % 2 == 0){
return false;
}
}
return true;
}
This is the correct way to do it.
c++ does not have garbage collection. Instead, it does deterministic destruction of objects such as i. The way the compiler does this is by cleaning up the object once the scope it's in has ended, and then not allowing you to use that object afterwards.
int main()
{
{
int i;
} // scope of i ends
cout << i; // error, can't access i here
}
for loops have their own scope, so in your example, the i in the first loop is not accessible in the second loop.

Error redeclaring a for loop variable within the loop

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.

for loop variable optimization in C/C++

Which is faster in following two code snippets? and Why?
Declared loop index variable outside the for statement:
size_t i = 0;
for (i = 0; i < 10; i++)
{
}
and
Declared loop index variable within the for statement:
for (size_t i = 0; i < 10; i++)
{
}
Neither, they are equivalent and will yield the same machine code.
(The compiler will remove the redundant initialization of i twice from the first example.)
Where a variable is declared has very little to do with performance and memory use.
for (size_t i = 0; i < 10; i++) is usually considered the most readable.
for (i = 0; i < 10; i++) has the advantage that you can use the i variable after the loop is done - which makes most sense when the number of iterations is variable.
The only difference is that on the fist one, i is a global variable, and the second one is a local variable only for the loop.

Why do I get an error when I compile the following code in GCC 4.9.2?

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';
}

What does it mean when the first "for" parameter is blank?

I have been looking through some code and I have seen several examples where the first element of a for cycle is omitted.
An example:
for ( ; hole*2 <= currentSize; hole = child)
What does this mean?
Thanks.
It just means that the user chose not to set a variable to their own starting value.
for(int i = 0; i < x; i++)
is equivalent to...
int i = 0;
for( ; i < x; i++)
EDIT (in response to comments): These aren't exactly equivalent. the scope of the variable i is different.
Sometimes the latter is used to break up the code. You can also drop out the third statement if your indexing variable is modified within the for loop itself...
int i = 0;
for(; i < x;)
{
...
i++
...
}
And if you drop out the second statement then you have an infinite loop.
for(;;)
{
runs indefinitely
}
The for construct is basically ( pre-loop initialisation; loop termination test; end of loop iteration), so this just means there is no initialisation of anything in this for loop.
You could refactor any for loop thusly:
pre-loop initialisation
while (loop termination test) {
...
end of loop iteration
}
Some people have been getting it wrong so I just wanted to clear it up.
int i = 0;
for (; i < 10; i++)
is not the same as
for (int i = 0; i < 10; i++)
Variables declared inside the for keyword are only valid in that scope.
To put it simply.
Valid ("i" was declared outside of the loops scope)
int i = 0;
for (; i < 10; i++)
{
//Code
}
std::cout << i;
InValid ("i" does not exist outside the loop scope)
for (int i = 0; i < 10; i++)
{
//Code
}
std::cout << i;
It means that the initial value of hole was set before we got to the loop
That means loop control variable is initialized before the for loop .
For C code,
int i=0;
for( ; i <10 ; i++) { } //since it does not allow variable declaration in loop
For C++ code,
for(int i=0 ; i <10 ; i++) { }
You could omit any of the parameters of a for loop.
ie: for(;;) {} is about the same as while(true) {}
It means that the initial value of hole was set before we got to the loop.
Looks like a list traversal of some kind.
Suppose you wanted to
for (hole=1 ; hole*2 <= currentSize; hole = child)
But the value of hole just before the for loop was already 1, then you can slip this initilization part of the loop:
/* value of hole now is 1.*/
for ( ; hole*2 <= currentSize; hole = child)