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

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

我有两个问题

  1. 为什么我没有重新申报错误?
  2. 为什么输出将是10 5次而不是10 1次?

这一切都与标识符的范围有关。 标识符只是在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

内部的范围在for循环体的闭合支撑处完成,因此,当检查for循环的延续条件时,它再次看到外部i 。 这就是为什么它循环五次而不是一次。

在你的代码中

  • 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被视为单独的变量 ,尽管被命名为相同。

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

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

你没有重新声明我,因为i(’int i = 10’)的第二个声明是在循环中。 这意味着在您的示例中,变量将被销毁并为循环的每次迭代重新创建。

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

Ps:如果你想通过改变i的值来停止循环

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

如果你很好地问你的编译器( gcc -Wshadow )它会警告你

  echo -e '#include \nvoid f(void) { int i; for (i = 0; i < 5; i++) { int i = 10; printf("%d", i); } }' | gcc -Wshadow -xc -c - 
 :在函数'f'中:
 :2:53:警告:声明“我”阴影前一个本地[-Wshadow]
 :2:20:注意:阴影声明就在这里