C++ array size dependent on function parameter causes compile errors
What you have found it one of the Gnu compiler's extensions to the C++ language. In this case, Visual C++ is completely correct. Arrays in C++ must be defined with a size that is a compile-time constant expression.
There was a feature added to C in the 1999 update to that language called variable length arrays, where this is legal. If you can find a C compiler that supports C99, which is not easy. But this feature is not part of standard C++, not is it going to be added in the next update to the C++ standard.
There are two solutions in C++. The first is to use a std::vector, the second is just to use operator new []
:
char *a = new char [n];
While I was writing my answer, another one posted a suggestion to use _alloca. I would strongly recommend against that. You would just be exchanging one non-standard, non-portable method for another one just as compiler-specific.
Warnings on too-small array sizes to functions in C/C++
Since asking this question, cppcheck has added this feature in response to my suggestion (thanks guys!),
Commit:
https://github.com/danmar/cppcheck/commit/7f6a10599bee61de0c7ee90054808de00b3ae92d
Issue:
http://sourceforge.net/apps/trac/cppcheck/ticket/4262
At the time of writing this isn't yet in a release, but I assume it will be in the next release.
Why there is no compile error for the array definition with non-constant value?
Both gcc and clang and possibly others although not visual C++, supports variable length arrays an extension even though it is a C99 feature not a C++ feature.
In both gcc
and clang
if you compile with -pedantic
they will warn you that you are using extensions, for example gcc
would produce a similar warning to this:
warning: ISO C++ forbids variable length array ‘allData’ [-Wvla]
and you can use -pedantic-errors
to turn the warning into an error.
As far as I understand C++14 may support variable length arrays. The C99 draft standard section 6.7.5.2
Array declarators says:
[...] If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.
while the C++ draft standard requires a constant, the draft C++ standard in section 8.3.4
Arrays says:
In a declaration T D where D has the form
D1 [ constant-expressionopt] attribute-specifier-seqopt
[..] If the constant-expression (5.19) is present, it shall be a converted constant expression of type std::size_t and its value shall be greater than zero. [...]
I passed the wrong length of an array to a function. Why do I not get an error?
I didn't give me any error ? No, compiler won't produce any error in this case since you are just passing the no of element value which is more than array element, But if name()
function tries to access out of bound elements then it cause undefined behavior. For e.g
void name(int[], int);
int main() {
int arr[] = {1,2,3};
name(arr, 5);
getch();
return 0;
}
void name(int a[], int i) {
printf("%d", i); /* printing variable i value is fine */
for(int row = 0; row < i; row++) {
printf("%d\n",a[row]);/* it cause UB when access a[3],a[4].. */
}
The correct procedure is find the no of element in array, store into one variable & pass that variable to a function, not some random number. For e.g
#include <stdio.h>
#include <stdio.h>
#include <conio.h>
void name(int[], int);
int main() {
int arr[] = {1,2,3},ele;
ele = sizeof(arr)/sizeof(arr[0]);
name(arr, ele);
getch();
return 0;
}
void name(int a[], int ele) {
printf("no of element in array : %d\n", ele);
for(int row =0; row<ele; row++) {
printf("%d\n",a[row]);
}
}
How to have array size depending on parameter in class using template
You can use Constexpr If (since C++17) with template parameter Q
as:
if constexpr (Q==3)
depot = {0,0,0};
else
depot = {0,0,0,0,0,0};
According to the condition value, the statement-true or statement-false will be discarded and then won't cause the error.
Before C++17, you can specify create_nodes
as:
template <>
void DARP<3>::create_nodes()
{
depot = {0,0,0};
}
template <>
void DARP<6>::create_nodes()
{
depot = {0,0,0,0,0,0};
}
C++ matrix size depending input doesn't compile
The array-new operator only allocates 1-dimensional arrays. There are different solutions, depending on what sort of array structure you want. For dimensions only known at runtime, you can either create an array of arrays:
char **a = new char*[rows];
for (int i = 0; i < rows; ++i) {
a[i] = new char[columns];
}
or an array of elements with an associated array of pointers to the first element of each row (requiring just two hits to the memory allocator):
char *a = new char[rows*columns];
char **a = new char*[rows];
for (int i = 0; i < rows; ++i) {
a[i] = a + i*columns;
}
Either one will let you access matrix elements via a[row][column]
.
An alternate solution is to just use the one-dimensional array and generate indexes by hand:
char *a = new char[rows*columns];
...
a[columns*row + column]
This is probably faster than the double-indirection required in the first two solutions.
You could of course wrap this in a class to preserve a semblance of 2D indexing syntax:
class MatrixWrapper {
...
char& operator()(int row, int column) { return a_[columns*row + column]; }
...
};
...
a(row, column)
Array-size macro that rejects pointers
Linux kernel uses a nice implementation of ARRAY_SIZE
to deal with this issue:
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
with
#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
and
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
Of course this is portable only in GNU C as it makes use of two instrinsics:
typeof
operator and __builtin_types_compatible_p
function. Also it uses their "famous" BUILD_BUG_ON_ZERO
macro which is only valid in GNU C.
Assuming a compile time evaluation requirement (which is what we want), I don't know any portable implementation of this macro.
A "semi-portable" implementation (and which would not cover all cases) is:
#define ARRAY_SIZE(arr) \
(sizeof(arr) / sizeof((arr)[0]) + STATIC_EXP(IS_ARRAY(arr)))
with
#define IS_ARRAY(arr) ((void*)&(arr) == &(arr)[0])
#define STATIC_EXP(e) \
(0 * sizeof (struct { int ARRAY_SIZE_FAILED:(2 * (e) - 1);}))
With gcc
this gives no warning if argument is an array in -std=c99 -Wall
but -pedantic
would gives a warning. The reason is IS_ARRAY
expression is not an integer constant expression (cast to pointer types and subscript operator are not allowed in integer constant expressions) and the bit-field width in STATIC_EXP
requires an integer constant expression.
Related Topics
Should I Still Return Const Objects in C++11
Understanding Rvalue References
How to Call a Cmake Function from Add_Custom_Target/Command
How Concatenate a String and a Const Char
How to Ignore False Positive Memory Leaks from _Crtdumpmemoryleaks
Stl Ordering - Strict Weak Ordering
What Does the "::" Mean in "::Tolower"
What Exactly Is a Namespace and Why Is It Necessary
Good C++ Solutions to the "Bring All the Zeros to the Back of the Array" Interview Challenge
C++ Virtual Function Table Memory Cost
Threadsafe Vector Class for C++
How Does the Friend Keyword (Class/Function) Break Encapsulation in C++
The Cxx Compiler Identification Is Unknown