C++ Array Size Dependent on Function Parameter Causes Compile Errors

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



Leave a reply



Submit