Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ array size dependent on function parameter causes compile errors

I have a simple function in which an array is declared with size depending on the parameter which is int.

    void f(int n){
        char a[n];
    };

    int main() {
        return 0;
    }

This piece of code compiles fine on GNU C++, but not on MSVC 2005.

I get the following compilation errors:

    .\main.cpp(4) : error C2057: expected constant expression
    .\main.cpp(4) : error C2466: cannot allocate an array of constant size 0
    .\main.cpp(4) : error C2133: 'a' : unknown size

What can I do to correct this?

(I'm interested in making this work with MSVC,without using new/delete)

like image 541
xxxxxxx Avatar asked Nov 23 '08 04:11

xxxxxxx


7 Answers

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.

like image 101
Jack Klein Avatar answered Oct 13 '22 19:10

Jack Klein


Your method of allocating from the stack is a g++ extension. To do the equivalent under MSVC, you need to use _alloca:

char *a = (char *)_alloca(n);
like image 21
Jim Buck Avatar answered Oct 13 '22 19:10

Jim Buck


You are using something that is not a standard. Actually it is standard C but not C++. How peculiar is that!

Explaining a bit more, run time sized stack arrays are not part of C++, but are part of C99, the latest standard for C. That´s why some compilers will get it, while others will not. I would recommend refrain from using it, to avoid compiler compatibility issues.

The alternate implementation of the functionality would be using new and delete, as posted by strager.

like image 28
David Reis Avatar answered Oct 13 '22 19:10

David Reis


You can use new/delete to allocate/free memory on the heap. This is slower and possibly more error prone than using char[n], but it's not part of the C++ standard yet, sadly.

You can used boost's scoped array class for an exception-safe method for using new[]. delete[] is automatically called on a when it goes out of scope.

void f(int n) {
    boost::scoped_array<char> a(new char[n]);

    /* Code here. */
}

You can also use std::vector, and reserve() some bytes:

void f(int n) {
    std::vector<char> a;
    a.resize(n);

    /* Code here. */
}

If you do want to use char[n], compile as C99 code instead of C++ code.

If you absolutely must allocate data on the stack for some reason, use _alloca or _malloca/_freea, which are extensions provided by MSVC libs and such.

like image 43
strager Avatar answered Oct 13 '22 21:10

strager


variable length array was introduced in C99. It is supported in gcc but not msvc. According to a person in MSVC team, Microsoft has no plan to support this feature in their c/C++ compiler. He suggested to use std::vector in those cases.

Note that C99 does not require that the array allocated on the stack. The compiler can allocate it on the heap. However, gcc does allocate the array on the stack.

like image 26
cuteCAT Avatar answered Oct 13 '22 21:10

cuteCAT


Typically in C (excepting C99 compilers as others have pointed out) and C++, if you want to allocate memory on the stack, the size of what you want to allocate has to be known at compile time. Local variables are allocated on the stack, so an array whose length depends on a function parameter at run time violates this rule. Klein is correct to point out that using the 'new' operator is one way to solve this problem:


char *a = new char [n];

'a' is still a local variable allocated on the stack, but instead of being the whole array (which has variable length), it's just a pointer to an array (which is always the same size, and thus known at compile time). The array is allocated on the heap, which typically plays the stack's counterpart -- the stack is for things with a size known at compile time, and the heap is for things with a size not known at a compile time.

like image 40
Joseph Garvin Avatar answered Oct 13 '22 19:10

Joseph Garvin


Would it be reasonable to use a vector<> rather than an array? Or, since you're replacing a char *, a std::string? Those do work well with runtime sizing, although there may be other reasons not to use them.

like image 33
David Thornley Avatar answered Oct 13 '22 19:10

David Thornley