为什么在循环外部和内部声明具有相同名称的变量会产生错误?

时间:2015-05-13 07:35:39

标签: c loops for-loop scope

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

我有两个问题

  1. 为什么i没有重新声明错误?
  2. 为什么输出将是10 5次,而不是10 1次?

4 个答案:

答案 0 :(得分:4)

这一切都与标识符的范围有关。标识符只是在C中赋予实体(对象,函数,typedef名称等)的名称,并且根据C11 6.2.1 /1

  

相同的标识符可以表示程序中不同点的不同实体。

该部分的/2中描述了实体的范围:

  

对于标识符指定的每个不同实体,标识符仅在称为其范围的程序文本区域内可见(即,可以使用)。

/4涵盖了您的具体案例:

  

如果标识符指定同一名称空间中的两个不同实体,则范围可能会重叠。如果是这样,一个实体(内部范围)的范围将严格地在另一个实体(外部范围)的范围之前结束。

换句话说,比如:

{
    int i = 42;
    printf ("%d ", i);
    {
        int i = 17;
        printf ("%d ", i);
    }
    printf ("%d\n", i);
}

完全有效,并会打印42 17 42。那是因为内部块中的标识符i位于其自己的范围内,该范围以第一个右括号结束。

在您的特定情况下,您可以将其视为:

{
    int i;              \
    for(i=0;i<5;i++)     > outer i scope
    {                   /
        int i=10;       \
        printf("%d",i);  > inner i scope
    }                   /
}

内部int i=10有效隐藏i循环体的持续时间for。这就是为什么它打印了很多10而不是0..4

内部i的范围在for循环体的右括号处结束,这样,当检查for循环的连续条件时,它再次看到外i。这就是为什么它循环五次而不是一次。

答案 1 :(得分:1)

在您的代码中

  • int i;位于外部区块范围内。
  • int i=10;位于for循环
  • 的内部块范围内

如果我们想象一下,我们可以提出像'

这样的东西
{                   //---------------------------|
    int i;                                       |
    for(i=0;i<5;i++)                             |
    {                                            |
        int i=10;       //-------| inner scope   |> Outer scope
        printf("%d",i); //-------|               |
    }                                            |
}                  //----------------------------|

这里的情况是,内部 i 阴影外部i。这两个被视为单独变量(基于其范围)。

换句话说,(内部范围)中定义和存在的i将具有更多优先级(超出外部范围中的变量)。因此,内部i值将被打印。

OTOH,循环计数器变量i保留在外部范围。它的价值不会因为街区内的分配而改变。所以,正如所问的那样,它正好循环了5次。

相关:来自C11标准,章节§6.2.1,第4段,

  

.. [..] .. 如果标识符指定同名的两个不同实体   空间,范围可能重叠。如果是这样,一个实体的范围(内部范围)将严格地在另一个实体(外部范围)的范围之前结束。在内部范围内,标识符指定在内部范围内声明的实体;在外部范围内声明的实体在内部范围内是隐藏(并且不可见)。

所以,回答你的问题,

  

为什么i没有重新声明错误?

因为两个i被视为单独变量,尽管名称相同。

  

为什么输出将是10 5次,而不是10 1次?

因为,用作计数器的外部i不会从循环内部更改,只有循环增量条件才会改变该值。

答案 2 :(得分:0)

由于i的第二个声明(&#39; int i = 10&#39;)位于循环内,因此您不会重新声明我。这意味着在您的示例中,变量将被销毁并为循环的每次迭代重新创建。

在任何复合语句中创建的变量范围仅限于复合语句本身。

Ps:如果你想通过改变i

的值来停止循环
{  
int i;  
for(i=0;i<5;i++)  
{  
i=10;  
printf("%d",i);  
}  
}  

答案 3 :(得分:0)

如果您很好地询问编译器(gcc -Wshadow),它会发出警告

 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