Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
}

Output:

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 

I'm using gcc 6.3, in https://www.codechef.com/ide

I'm expecting the first row to be all zeros. Shouldn't that be the case?

EDIT: I tested with const variables for rows and cols, and then it initialized to all zeroes. I feel this should throw a compile error instead of exhibiting this incorrect (and potentially dangerous) behavior.

like image 487
dev_nut Avatar asked Aug 31 '18 16:08

dev_nut


People also ask

How do you initialize a 2D array to 0?

int array [ROW][COLUMN] = {0}; which means: "initialize the very first column in the first row to 0, and all other items as if they had static storage duration, ie set them to zero." int array [ROW][COLUMN] = {1}; it means "initialize the very first column in the first row to 1 and set all other items to zero".

How do you initialize values in a two-dimensional array?

On the other hand, to initialize a 2D array, you just need two nested loops. 6) In a two dimensional array like int[][] numbers = new int[3][2], there are three rows and two columns. You can also visualize it like a 3 integer arrays of length 2. You can find the number of rows using numbers.

How do you initialize an array with zero values?

1. Using Initializer List. int arr[] = { 1, 1, 1, 1, 1 }; The array will be initialized to 0 if we provide the empty initializer list or just specify 0 in the initializer list.


2 Answers

If we look at the gcc 4.9 release notes it looks like they added support for initializating VLA with the expectation VLA would be supported in a future version of C++:

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.

We can see it live that before 4.9 complains we can't initialize a VLA

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

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

So it looks like a regression.

Note that clang refuses to allow initialization of a 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 Bug 69517

gcc bug report :SEGV on a VLA with excess initializer elements has a comment that provides some background on this feature:

(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.)

like image 113
Shafik Yaghmour Avatar answered Oct 05 '22 06:10

Shafik Yaghmour


This appears to be a GCC bug, and the desired behavior is most likely that this shouldn't compile. C99 supports variable-length arrays, but refuses to initialize them: C initializers need to know their type at compile-time, but the type of a variable-length array can't be complete at compile-time.

In GCC, C++ gets variable-length arrays as an extension from its C99 support. Therefore, the behavior governing variable-length array initialization in C++ isn't established by a standard. Clang refuses to initialize a variable-length array even in C++.

Note that even = {0} is technically sort of dangerous (if it worked at all): if rows and cols are 0, you'll be overflowing. Memset is probably your best option.

like image 42
zneak Avatar answered Oct 05 '22 08:10

zneak