具有可变长度数组的代码顺序

时间:2016-07-07 02:06:09

标签: c variable-length-array

在C99中,这两者之间有很大不同吗?:

int main() {
    int n , m;
    scanf("%d %d", &n, &m);
    int X[n][m];

    X[n-1][m-1] = 5;
    printf("%d", X[n-1][m-1]);
}

int main(int argc, char *argv[]) {
    int n , m;
    int X[n][m];
    scanf("%d %d", &n, &m);

    X[n-1][m-1] = 5;
    printf("%d", X[n-1][m-1]);
}

第一个似乎总能工作,而第二个似乎适用于大多数输入,但为输入5 56 6提供了段错误,并为输入返回不同于5的值9 9。那么你需要确保在使用可变长度数组声明它们之前得到这些值,或者这里还有其他东西吗?

3 个答案:

答案 0 :(得分:4)

当第二个工作时,这是纯粹的机会。它曾经有效的事实证明,幸运的是,编译器还不能make demons fly out of your nose

声明变量不一定要初始化它。在这种情况下,int n, m;会为nm留下未定义的值,并且尝试访问这些值是未定义的行为。如果内存中的原始二进制数据指向发生,则会将其解释为大于为nm输入的值的值 - 这是非常非常远的从保证 - 然后你的代码将工作;如果没有,它不会。您的编译器也可以使这个段错误,或者使它融化您的CPU;它是未定义的行为,所以任何事情都可能发生。

例如,假设编译器专用于n的内存区域恰好包含数字10589231,而m包含14。如果你输入了一个12的n和一个6的m,你就是金色的 - 阵列恰好足够大了。另一方面,如果n得到4并且m得到2,那么你的代码将看起来超过数组的末尾,你会得到未定义的行为 - 甚至可能不会破坏,因为根据编译器/ C标准,数组结束后存储在四字节段中的位完全有可能被程序访问,并且有效整数。此外,nm可能会以负值结束,从而导致......奇怪的东西。可能。

当然,根据编译器,操作系统,一天中的时间和月亮的阶段, 1 ,所有这些都是粗暴和猜测,你不能依赖任何正在发生的数字来初始化到正确的。

另一方面,对于第一个,你通过scanf分配值,所以(假设它没有错误)(并且输入的数字不是负数)(或为零)你'将拥有有效的索引,因为数组保证足够大,因为变量已正确初始化。

需要明确的是,即使在某些情况下要求变量零初始化并不意味着您应该依赖该行为。您应该始终明确地为变量赋予默认值,或者在声明之后尽快初始化它们(在使用scanf之类的情况下)。这使您的代码更加清晰,并且可以防止人们想知道您是否依赖这种类型的UB。

1:来源:Ryan Bemrose,聊天

答案 1 :(得分:4)

n表示声明一个数组,其维度是mn当前具有的值。 C代码不会考虑未来;语句和声明按它们遇到的顺序执行。

在您的第二个代码中,您没有提供mint x = 5; printf("%d\n", x); x = 7; 值,因此这是未定义的行为,这意味着可能发生任何事情。

这是顺序执行的另一个例子:

5

这将打印7,而不是{{1}}。

答案 2 :(得分:-1)

第二个应该产生错误,因为如果它们是局部变量,则n和m用相当多的随机值初始化。如果它们是全球性的,它们将具有价值0。