在 gcc 中将二维数组初始化为 0 时的值不正确

Incorrect values when initializing a 2D array to 0 in gcc

#include <iostream>
using namespace std;

int main() {

    int rows = 10;
    int cols = 9;
    int opt[rows][cols] = {0};

         for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                std::cout << opt[i][j] << " ";
            }
             std::cout << "\n";
         }

    return 0;
}

输出:

0 32767 1887606704 10943 232234400 32767 1874154647 10943 -1 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 

我在 https://www.codechef.com/ide

中使用 gcc 6.3

我希望第一行全为零。不应该是这样吗?

编辑:我用 const 变量测试行和列,然后将其初始化为全零。我觉得这应该抛出一个编译错误,而不是表现出这种不正确(和潜在危险)的行为。

这似乎是一个 GCC 错误,所需的行为很可能是不应该编译的。 C99 支持可变长度数组,但拒绝对其进行初始化:C 初始化程序需要在编译时知道它们的类型,但可变长度数组的类型在编译时无法完成。

在 GCC 中,C++ 将可变长度数组作为其 C99 支持的扩展。因此,在 C++ 中管理可变长度数组初始化的行为不是由标准建立的。即使在 C++ 中,Clang 也拒绝初始化可变长度数组。

请注意,即使 = {0} 在技术上也有点危险(如果它有效的话):如果 rowscols 为 0,您将溢出。 Memset 可能是您的最佳选择。

如果我们查看 gcc 4.9 release notes,他们似乎添加了对初始化 VLA 的支持,并期望 C++ 的未来版本支持 VLA:

G++ supports C++1y variable length arrays. G++ has supported GNU/C99-style VLAs for a long time, but now additionally supports initializers and lambda capture by reference. In C++1y mode G++ will complain about VLA uses that are not permitted by the draft standard, such as forming a pointer to VLA type or applying sizeof to a VLA variable. Note that it now appears that VLAs will not be part of C++14, but will be part of a separate document and then perhaps C++17.

我们可以看到 it live that before 4.9 抱怨我们无法初始化 VLA

error: variable-sized object 'opt' may not be initialized  
     int opt[rows][cols] = {0};  
                             ^

但在 4.9.1 and after it stops complaining and it does not have the same bug we see in more recent versions.

所以看起来像是回归。

请注意,clang 不允许初始化 VLA (which they support as an extension) see a live example. Which make sense since C99 does not allow initialization of VLA:

The type of the entity to be initialized shall be an array of unknown size or an object type that is not a variable length array type.

gcc 错误 69517

gcc bug report :SEGV on a VLA with excess initializer elements 有一条评论提供了有关此功能的一些背景信息:

(In reply to Jakub Jelinek from comment #16)

The bug here is in G++ accepting a VLA initializer with more elements than there is room for in the VLA, and then trashing the stack at runtime with the extra elements. It is a regression with respect to GCC 4.9.3 which implements C++ VLAs as specified in n3639 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3639.html). This is documented in GCC 4.9 changes (https://gcc.gnu.org/gcc-4.9/changes.html) which highlights the feature using the following example:

  void f(int n) {
    int a[n] = { 1, 2, 3 }; // throws std::bad_array_length if n < 3
    ...

VLAs were subsequently removed from C++, and also partially (but not completely) removed from G++, which causes C++ programs developed and tested with G++ 4.9 to break when ported to a later version.

C++ VLAs will be safer to use with the patch referenced in comment #9. It patch had to be reverted from GCC 6.0 because it caused problems in Java. Java has been removed and I plan/hope to resubmit the patch for GCC 8. (I wanted to do it for GCC 7 but didn't get to it.)

我发布这个问题是为了了解我的代码或 gcc 有什么问题。但是,这就是我在 C++ 中的做法。对于可变长度数组要求,使用向量而不是数组。

#include <iostream>
#include <vector>

int main() {

    int rows = 10;
    int cols = 9;

    std::vector<std::vector<int>> opt(rows, std::vector<int>(cols, 0));

         for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                std::cout << opt[i][j] << " ";
            }
             std::cout << "\n";
         }

    return 0;
}

输出:

0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0