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:
char vla_buf[n < 1000 ? n : 1];
char *buf = sizeof vla_buf < n ? malloc(n) : vla_buf;
if (!buf) goto error;
/* ... Do stuff with buf ... */
if (buf != vla_buf) free(buf);
While this looks like useless pain, it can make a huge performance difference, especially in threaded applications where many calls to malloc
and free
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]
with 1000
, 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
, where n
is small enough you're confident it won't overflow the stack, but where there could be up to n
levels of recursion and individual levels that use up to n
elements. Prior to C99, the only way to handle this case without taking n^2
stack space was to use malloc
. 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:
#define MAX_VLA 10000
int bar(size_t n)
{
int arr[n <= MAX_VLA ? n : 1];
if (sizeof arr/sizeof *arr < n) return ENOMEM;
/* ... */
return 0;
}