在C中循环重新声明VLA数组

时间:2014-07-29 17:42:14

标签: c c99

这是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的规则/引用,或者它只是编译器的错误

2 个答案:

答案 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涵盖了一个更为复杂的案例,我也有答案。