Why doesn't declaring a variable with the same

2019-03-07 07:31发布

问题:

{  
    int i;  
    for(i=0;i<5;i++)  
    {  
        int i=10;  
        printf("%d",i);  
    }  
}  

I have two questions

  1. Why is there no redeclaration error for i?
  2. why output will be 10 5 times and not 10 1 time?

回答1:

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 10s 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.



回答2:

In your code

  • int i; is in outer block scope.
  • int i=10; is in the inner block scope for the for loop

If 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 is are treated as seperate variable, despite being named same.

why output will be 10 5 times and not 10 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.



回答3:

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


回答4:

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