0

Here is a small sample of the code which I am trying to run:

#include <iostream>
using namespace std;

int main() {
    int t1 = 7;
    int t2 = 5;

    float arr[t1][t2] = {0};
    //float arr[t1][t2] = {{0},{0},{0},{0},{0},{0},{0}};
    
    for(int i=0; i<t1; i++)
    {
        for(int j=0; j<t2; j++)
            cout << arr[i][j];

        cout<<endl;
    }

    return 0;
}

In the above code, I have shown two ways of initializing the array arr of float data type. But both ways, the code fails to provide the required output, which is a 2D array containing all zeros. However if I just change the data type from float to double the code works perfectly fine (seems strange/confusing to me).

Can someone help me out if there is any conceptual error in the code or is there any specific reason because of which it doesn't work the way I intend to?

I know there is a way(shown below) where we can intialize using calloc, but when the matrix is a 2-dimensional one, we have to use a for loop to initialize each row of the array, which is not a faster way (if the number of rows/columns are of larger size).

float **arr = new float *[t1];
    for(int i=0; i<t1; i++)
    {
        arr[i] = (float*)calloc(t2,sizeof(float));
    }
5
  • 3
    float arr[t1][t2] = {0} where t1 and t2 are variables is a (two-dimensional) variable-length array (VLA). VLAs are not valid in standard C++ - irrespective of how you try to initialise them. Commented Jul 18, 2021 at 10:07
  • 1
    Using a different compiler, clang says error: variable-sized object may not be initialized. Commented Jul 18, 2021 at 10:39
  • There's no C/C++ language. In C++ arr[t1][t2] is invalid Commented Jul 18, 2021 at 11:10
  • @phuclv • I'm working on a new programming language that I'm calling C/C++. It's a lot like OCaml. Commented Jul 18, 2021 at 11:19
  • I think a bug report to gcc asking for a diagnostic (and/or a change of behavior) would be a good idea. Commented Jul 18, 2021 at 12:54

2 Answers 2

2

Can someone help me out if there is any conceptual error in the code

The size of an array must be a compile time constant expression in C++. A non-const variable isn't a constant expression. Simple fix in this example is to declare the variables const (or constexpr):

const int t1 = 7;
const int t2 = 5;

Without this fix, the program is ill-formed.

This means that the program isn't valid C++ and the compiler isn't required to accept the program. The compiler is however required in this case to diagnose the issue. If the compiler does compile the program, then the C++ language doesn't specify how it should behave.


As shown in comments, it appears that the behaviour that you describe can be reproduced by using Variable Length Array extension of GCC.

The GCC documentation doesn't describe how the extension would behave if you provide initialisers for the elements. With experimentation, it appears that if you provide initialiser for any element, then the elements that aren't given an initialiser are not value initialised. This is contrary to how standard C++ arrays behave.


(if the number of rows/columns are of larger size)

If the number of rows or columns are of a large size, then you shouldn't use an automatic array such as in the example because the available memory for automatic variables is generally limited. Use std::vector in that case instead.


As an aside, it isn't necessary to provide initialiser for the first element of the array. You can omit it to value initialise all elements:

float arr[t1][t2] = {};
Sign up to request clarification or add additional context in comments.

5 Comments

This does not speak to the question the OP asks except to mention the program is “ill-formed”, which is not an explanation for a questioner new to the concept. The behavior is reproducible. Regardless of the limits of the C++, GCC accepts a variable-length array definition and accepts a list of initializers for it, but it appears to initialize only part of the array. However, if the list is empty ({}), it appears to initialize the entire array (even if it is variable-length). If the list is absent, it does not initialize the array at all. …
… If both dimensions are changed to const int, then GCC does appear to initialize the entire array given {0}. Even though this is an extension by GCC and hence not specified by the standard, it a strange way for an extension to behave and should be addressed.
@EricPostpischil which is not an explanation for a questioner new to the concept It is trivial to find the meaning of that concept. Learning how to find information based on name of a concept is a crucial skill that should be practiced. Regardless, I added a description.
@EricPostpischil GCC accepts a variable-length array definition Doing so without diagnosing the ill-formed program means that GCC doesn't conform to the C++ standard. This is unfortunate, but GCC can be made to behave: Using the -pedantic option, GCC tells what's wrong: warning: ISO C++ forbids variable length array 'arr' [-Wvla].
@EricPostpischil it a strange way for an extension to behave and should be addressed. I've now addressed it.
1

Your question involves behavior not covered by the C++ standard, so some explanation of the rules involved is necessary.

You do not state which C++ implementation you are using, but the behavior reproduces with GCC, so this answer presumes you are using GCC, and I use GCC 11.1 for reference.

By default, GCC does not conform to the C++ standard when compiling C++ source files. Per the last sentence of clause 2.2 of the GCC 11.1 documentation, the default language it uses is gnu++17, which is the “C++17 standard with GNU extensions.” This is a bit of a misnomer as gnu++17 is not just an extension of the 2017 C++ standard but varies from it.

In C++, array dimensions should be constant expressions, and the standard requires a C++ implementation to diagnose when they are not. Given int t1 = 7; and int t2 = 5;, t1 and t2 are not constant expressions as the C++ standard defines them. In gnu++17 mode, GCC does not diagnose this violation of the rule, so it is deviating from the standard, not just extending it.

The C standard allows defining arrays with variable lengths, and it is not an uncommon extension for a compiler to allow this in C++. However, the C standard does not allow for initializing a variable-length array (in that it requires a diagnostic for it, although a C implementation is allowed to accept the initialization).

So the program you show is two steps removed from the C++ standard, one for allowing variable-length arrays and another for initializing them, and the standard does not tell us what should happen. Further, in GCC’s documentation on its extensions to C++, I do not see mention of variable-length arrays, let alone initializing them. The section on extensions to C contains some discussion of variable-length arrays but no mention of initializing them.

Thus the GCC documentation also appears silent on what should happen.

Testing various source code in GCC’s gnu++17 mode suggests:

  • If you define a variable-length array with no initialization (no = … after the declarator, just ;), GCC does not initialize it. (I saw non-zero data throughout the array.)
  • If you define a variable-length array with some initializers (for example = { 1, 2 }), GCC initializes the elements corresponding to the initializers but not other elements.
  • If you define a variable-length array with an empty initializer list (= {}), GCC initializes the array to zero.
  • If you define the inner array dimension with a constant expression (for example, changing the t2 definition to const int t2 = 5;) and give some initializers, GCC initializes the entire array, using zeros for the elements without initializers. (I suspect this would be so for multidimensional arrays when all dimensions other than the outermost are constant expressions.) Thus, GCC initializes the fixed-length inner arrays even though there are a variable number of them.

In those results, I do not see evidence of an intended pattern. I suspect the behavior here has been overlooked by GCC developers. That is, I do not think the behavior in these various cases all result from deliberate decisions. It may be that initialization of a variable-length array initializes only those elements that are explicitly initialized (taking {} to mean all elements are initialized), leaving the others uninitialized (unlike initialization of fixed-length arrays).

I do not see the behavior you report with double; when I change float to double, I still see uninitialized elements containing non-zero values.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.