{
int i;
for(i=0;i<5;i++)
{
int i=10;
printf("%d",i);
}
}
I have two questions
- Why is there no redeclaration error for
i
? - why output will be
10
5 times and not10
1 time?
{
int i;
for(i=0;i<5;i++)
{
int i=10;
printf("%d",i);
}
}
I have two questions
i
?10
5 times and not 10
1 time?It all has to do with the scope of an identifier. An identifier is simply a name given to an entity (object, function, typedef name and so on) in C and, as per C11 6.2.1 /1
:
The same identifier can denote different entities at different points in the program.
The scope of an entity is described in /2
of that section:
For each different entity that an identifier designates, the identifier is visible (i.e., can be used) only within a region of program text called its scope.
And /4
covers your specific case:
If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope).
In other words, something like:
{
int i = 42;
printf ("%d ", i);
{
int i = 17;
printf ("%d ", i);
}
printf ("%d\n", i);
}
is perfectly valid, and will print 42 17 42
. That's because the identifier i
inside the inner block is in its own scope, which ends at the first closing brace.
In your particular case, you can think of it as:
{
int i; \
for(i=0;i<5;i++) > outer i scope
{ /
int i=10; \
printf("%d",i); > inner i scope
} /
}
The inner int i=10
effective hides the outer i
for the duration of the body of the for
loop. That's why it prints a lot of 10
s rather than 0..4
.
The scope of the inner i
finishes at the closing brace of the for
loop body so that, when the continuation condition of the for
loop is checked, it once again sees the outer i
. That's why it loops five times rather than once.
In your code
int i;
is in outer block scope.int i=10;
is in the inner block scope for the for
loopIf we visualize the same, we can come up with something like'
{ //---------------------------|
int i; |
for(i=0;i<5;i++) |
{ |
int i=10; //-------| inner scope |> Outer scope
printf("%d",i); //-------| |
} |
} //----------------------------|
The case here is, the inner i
will shadow the outer i
. These two are considered seperate variable (based on their scope).
In other words, the i
which is defined and present inside the block (inner scope) will have more preference (over the variable in outer scope). So, the inner i
value will get printed.
OTOH, the loop counter variable i
remains at the outer scope. It's value is not altered through the assignement inside the block. So, rightly it loops for 5 times, as asked.
Related: From C11
standard, chapter §6.2.1, paragraph 4,
..[..].. If an identifier designates two different entities in the same name space, the scopes might overlap. If so, the scope of one entity (the inner scope) will end strictly before the scope of the other entity (the outer scope). Within the inner scope, the identifier designates the entity declared in the inner scope; the entity declared in the outer scope is hidden (and not visible) within the inner scope.
So, to answer your questions,
Why is there no redeclaration error for i?
Because two i
s are treated as seperate variable, despite being named same.
why output will be
10
5 times and not10
1 time?
Because, the outer i
, used as the counter, is not changed from inside the loop, only the loop increment condition is altering that value.
You aren't re-declaring i since the second declaration of i ( 'int i =10' ) is inside a loop . That's means that in your example the variable is destroyed and recreated for each iteration of the loop .
The scope of variables created in any compound statement is limited to the compound statement itself .
Ps : If you wanted to stop the loop by changing the value of i
{
int i;
for(i=0;i<5;i++)
{
i=10;
printf("%d",i);
}
}
If you ask your compiler nicely (gcc -Wshadow
) it will warn you
echo -e '#include <stdio.h>\nvoid f(void) { int i; for (i = 0; i < 5; i++) { int i = 10; printf("%d", i); } }' | gcc -Wshadow -xc -c -
<stdin>: In function 'f': <stdin>:2:53: warning: declaration of 'i' shadows a previous local [-Wshadow] <stdin>:2:20: note: shadowed declaration is here