这是Redeclaring of an array in loop in C的后续行动以及我的一些额外观察。
考虑以下两个例子:
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 10) {
int t[10];
if (i == 1)
t[0] = 100;
else {
t[0]++;
printf("i = %d, t[0] = %d\n", i, t[0]);
}
i++;
}
return 0;
}
结果符合预期:
i = 2, t[0] = 101
i = 3, t[0] = 102
i = 4, t[0] = 103
i = 5, t[0] = 104
i = 6, t[0] = 105
i = 7, t[0] = 106
i = 8, t[0] = 107
i = 9, t[0] = 108
i = 10, t[0] = 109
和第二个(略有不同)与VLA(在C99中引入):
#include <stdio.h>
int main(void)
{
int i = 1;
while (i <= 10) {
int t[i];
if (i == 1)
t[0] = 100;
else {
t[0]++;
printf("i = %d, t[0] = %d\n", i, t[0]);
}
i++;
}
return 0;
}
我得到的第二个例子(在gcc 4.4.7中)对我来说很奇怪:
i = 2, t[0] = 101
i = 3, t[0] = 102
i = 4, t[0] = 103
i = 5, t[0] = 1
i = 6, t[0] = 2
i = 7, t[0] = 3
i = 8, t[0] = 4
i = 9, t[0] = 1637935601
i = 10, t[0] = 1637935602
在C标准中是否有针对在循环内声明的VLA的规则/引用,或者它只是编译器的错误?
答案 0 :(得分:5)
在这两种情况下,您都应该看到垃圾值。您的数组对象(VLA与否)在循环的每次迭代中再次开始其生命周期。每当它开始它的生命周期中,它具有不确定的价值。在你的第一个例子中,你很幸运,那些&#34;不确定&#34;值恰好与前一次迭代在内存中留下的值相同。同时,VLA的潜在机制是不同的,所以你只是没有用VLA获得幸运。
请注意,在C语言中,VLA和非VLA对象的生命周期的定义不同。非VLA对象在相应范围的开始{
开始它们的生命周期,而VLA对象在声明点开始其生命周期。甚至对于没有初始化程序定义的非VLA对象,当控制传递其定义时,它们会立即获取不确定的值。
但是这些细节在这里描述的情况很重要:GOTO before local variable。但是,这在您的具体示例中无关紧要,因为在您的示例中,两个数组都会在每次迭代时被销毁并重新创建。
答案 1 :(得分:2)
可变长度数组的生命周期从扩展延伸到范围的末尾。这在C99标准部分草案6.2.4
对象的存储持续时间中有所说明:
对于具有可变长度数组类型的对象,其生命周期从 对象的声明,直到程序的执行离开了范围 声明.27)如果以递归方式输入范围,则会创建该对象的新实例 每一次。对象的初始值是不确定的。
因此,您在此处调用未定义的行为,因为您使用的是不确定的值。
对于非变长数组,这是不同的,草案标准说:
对于没有可变长度数组类型的对象,其生命周期会延长 从进入与之关联的块直到该块的执行结束 无论如何。[...]
Rationale for International Standard—Programming Languages—C解释了原因:
对于可变长度数组,必须稍微修改这些规则。实施不会 知道数组在达到声明之前需要多少空间,因此在此之前无法创建它。
GOTO before local variable涵盖了一个更为复杂的案例,我也有答案。