【问题标题】:code order with variable length array具有可变长度数组的代码顺序
【发布时间】:2016-11-09 05:57:27
【问题描述】:

在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 提供段错误,并为输入 9 9 返回一个不同于 5 的值。那么在使用可变长度数组声明它们之前,您是否需要确保获取这些值,或者这里还有其他事情发生吗?

【问题讨论】:

  • 第二个是完全错误的......因为nm 没有初始化。 int X[n][m]; 使用代码中的 mn 值——您不能稍后设置它们,也不能通过稍后更改它们来调整数组的大小。
  • 好的,谢谢,我想确保它只是一个订购的东西,而不是我没有想到的其他东西。

标签: c variable-length-array


【解决方案1】:

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

声明一个变量并不一定会初始化它。在这种情况下,int n, m; 使 nm 都带有 undefined 值,并且尝试访问这些值是未定义的行为。如果内存中的原始二进制数据指向发生,将被解释为大于为nm 输入的值——这与保证相去甚远——那么您的代码将起作用;如果没有,它不会。你的编译器也可能造成了这个段错误,或者让它融化了你的 CPU;这是未定义的行为,所以任何事情都可能发生。

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

当然,这都是浮夸和推测,取决于编译器、操作系统、一天中的时间和月相,1 你不能依赖任何发生初始化的数字到正确的。

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


需要明确的是,即使在某些情况下需要对变量进行零初始化也不意味着您应该依赖这种行为。你应该总是显式地给变量一个默认值,或者在它们声明后尽快初始化它们(在使用类似scanf的情况下)。这使您的代码更清晰,并防止人们怀疑您是否依赖于这种类型的 UB。


1:来源:Ryan Bemrose,正在聊天中

【讨论】:

    【解决方案2】:

    int X[n][m]; 表示声明一个数组,其维度是nm 当前拥有的值。 C 代码不展望未来;语句和声明按照遇到的顺序执行。

    在您的第二个代码中,您没有提供 nm 值,因此这是未定义的行为,这意味着任何事情都可能发生。

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

    int x = 5;
    printf("%d\n", x);
    x = 7;
    

    这将打印5,而不是7

    【讨论】:

    • 这篇文章给人的感觉……不仅仅是有点讽刺和居高临下,tbh。也许是因为它是如此基本的东西对我来说似乎很明显,所以看到对它的任何解释听起来很屈尊。
    • @QPaysTaxes 我只是想说清楚,没有讽刺或屈尊的意思
    • 很公平。这可能都在我的脑海里。
    【解决方案3】:

    第二个应该会产生错误,因为如果 n 和 m 是局部变量,它们会使用几乎随机的值进行初始化。如果它们是全局的,它们的值为 0。

    【讨论】:

    • "任何版本的 C++" - VLA 是 C 的东西。 C++ 没有它们。
    • 哦,是的。你可以使用 C++ 并且仍然允许它们,所以我忘记了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-28
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    • 2017-11-02
    相关资源
    最近更新 更多