Reputation: 9
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));
}
Upvotes: 0
Views: 1339
Reputation: 222332
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:
= …
after the declarator, just ;
), GCC does not initialize it. (I saw non-zero data throughout the array.)= { 1, 2 }
), GCC initializes the elements corresponding to the initializers but not other elements.= {}
), GCC initializes the array to zero.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.
Upvotes: 1
Reputation: 238311
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] = {};
Upvotes: 2