Before variable-length arrays were supported, I would dynamically allocate them like this:
int foo(size_t n)
{
int *arr = malloc(n * sizeof int);
if (!arr) return ENOMEM; /* not enough memory */
.
. else do stuff with arr[]
.
free(arr);
return 0;
}
With variable-length arrays I can now make it look cleaner:
int bar(size_t n)
{
int arr[n];
.
. do stuff with arr[]
.
return 0;
}
But now I have no "out of memory" checking. In fact, the program crashes if n is too big.
How can I gracefully bail from bar(n) if n is too big?
You can prevent them from crashing by not using them. :)
In all seriousness, there is almost no safe way to use variable-length arrays to make your life easier unless you have strong bounds on the size. On the other hand, you can use them conditionally, in ways like this:
While this looks like useless pain, it can make a huge performance difference, especially in threaded applications where many calls to
malloc
andfree
could result in lock contention. (A notable side benefit of this trick is that you can support old compilers without VLAs by simply replacing[n < 1000 ? n : 1]
with1000
, e.g. with a macro.)Another obscure case where VLAs may be useful is in recursive algorithms where you know the total number of array entries required across all levels of recursion is bounded by
n
, wheren
is small enough you're confident it won't overflow the stack, but where there could be up ton
levels of recursion and individual levels that use up ton
elements. Prior to C99, the only way to handle this case without takingn^2
stack space was to usemalloc
. With VLAs, you can solve the problem entirely on the stack.Keep in mind, these cases where VLAs are really beneficial are pretty damn rare. Normally VLA is just a way to deceive yourself that memory management is easy, until you get bit by the resulting (trivial-to-exploit) vulnerabilities you've created. :-)
Edit: To better address OP's original question:
The situation is exactly unchanged from any other local variables - a declaration like this:
has exactly the same problem. The "solution" is the same as it always has been - don't recurse too deeply, and don't allocate very large data structures with automatic storage duration (continue to use
malloc()
for these cases). The value of "very large" depends strongly upon your environment.In other words, don't declare
int array[n];
unless you know thatn
is bounded to a reasonable value, such that you would have been happy to declare an array of that maximum size as an ordinary, non-variably-modified type array.(Yes, this means that variably-modified type arrays are not as useful as they first appear, since you gain very little over just declaring the array at the maximum needed size).
In reality it is prohibitively expensive to check for out of memory conditions everywhere. The enterprisy way to deal with massive data is to limit data sizes by defining hard cap on size at single early checkpoint and fail fast and gracefully when the cap is hit.
What I just suggested is simple and stupid. But its what every ordinary (non-scientific or special) product always does. And its what normally is expected by customer.