0

When is it better to instantiate a variable length array with calloc vs. "normal" array declaration in C?

Consider the 'array declaration' approach:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{

    int n = atoi(argv[1]);
    int x[n];

    for(int i = 1; i < n; i++){
        x[i] = i;
        printf("%i", x[i]);
        printf("\n");
    }
    return 0;
}

vs. the calloc approach:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{

    int n = atoi(argv[1]);
    int * x = (int*) calloc(n, sizeof(int));

    for(int i = 1; i < n; i++){
        x[i] = i;
        printf("%i", x[i]);
        printf("\n");
    }
    return 0;
}

Should you always use one or the other? Is one faster than the other (e.g. bc of stack vs heap allocation)? Is one a lot riskier than the other?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
rlh2
  • 1,039
  • 2
  • 9
  • 16
  • 4
    VLAs are deprecated by some reputable folks like [Linus Torvalds](https://lkml.org/lkml/2018/3/7/621). And for a reason - these are allocated on stack *uncontrollably* - that is, C has no mechanisms of detecting if it is overflowing the stack, unlike with the dynamic allocation (well, in your code you are not checking it as well, but you could). – Eugene Sh. Jan 31 '22 at 19:54
  • 2
    Non-compile-time-deterministic automatic storage allocation should be avoided where at all possible (and it is *almost* always possible). – WhozCraig Jan 31 '22 at 20:00
  • Frankly, I'd discourage you from using VLAs unless you were *REALLY* sure they're "ideal" for *YOUR PARTICULAR USE CASE*. Here's some useful discussion: https://stackoverflow.com/questions/22530363/whats-the-point-of-vla-anyway. I'd prefer: 1) declaring a fixed-size array, 2) using malloc(). – paulsm4 Jan 31 '22 at 20:04
  • 1
    @EugeneSh., Linus is influential, but he does not have the power or authority to *deprecate* any feature of the C language. He can dislike them, discourage their use, refuse to accept them in the Linux kernel, and various other things, but "deprecating" features is something that only the standard committee can do. – John Bollinger Jan 31 '22 at 20:05
  • @JohnBollinger You are probably right and my wording is an artifact of not being a native English speaker. – Eugene Sh. Jan 31 '22 at 20:06
  • @EugeneSh. *And for a reason - these are allocated on stack uncontrollably - that is, C has no mechanisms of detecting if it is overflowing the stack* VLAs are not limited to being instantiated on the stack, and in general C has no way of detecting if *anything* overflows the stack for any reason. VLAs are no more nor less dangerous than C as a whole - if you don't know what you're doing, you shouldn't be using C. If you pick up a professional logger's 2-meter chainsaw and cut your leg off, that's your fault, not the tool's. – Andrew Henle Jan 31 '22 at 20:15
  • It is best to avoid VLAs. And in 99.999% of cases you don't need it. The rest 0.001% are answers in SO. – i486 Jan 31 '22 at 20:33
  • The "normal" way is only guaranteed to work on C99. C90 doesn't have it, and now it's an optional feature. – Neil Jan 31 '22 at 20:43
  • 1
    @i486 there is so much more to VLA than stack allocated arrays though. The VLA typesystem is what's great about it. One can for example now easily allocate a dynamic multi dimensional array with one malloc call. I agree with you that one should avoid vla arrays on the stack, but we should embrace the other benefits it brings. – Fredrik Jan 31 '22 at 20:48
  • all - thanks for all the answers/comments - really helpful! In general, I am only using C through R's C API where they provide an "R version" for c/malloc: https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Memory-allocation. I had always thought you were supposed to use c/malloc and was surprised when the ```int x[n];``` even compiled. I am only a C tourist, so didn't know too much about it! – rlh2 Jan 31 '22 at 20:53
  • @Neil: The "normal" way is likely to fail if the array size is "too big", and there is no size for which it is in any sense guaranteed to work. – supercat Jan 31 '22 at 21:57
  • @Fredrik: If one has a compiler with a decades-proven type system design which assumes objects will have fixed types, are the benefits of VLA types so great as to justify overhauling the type system and having to wait until 2042 before one could again have a decades-proven type system design? – supercat Jan 31 '22 at 22:20

5 Answers5

5
int x[n];

Automatic storage duration objects including VLAs are (by most modern implementations) allocated on the stack. There are some problems with the larger objects if they are allocated on the stack (three most important ones):

  1. There is no allocation control unless your program fails when you overflow the stack
  2. Stack is usually much much smaller than the heap. So the size of the array is limited
  3. The lifetime of the array is limited to the lifetime of the enclosing block. You can't return the reference to this array on the function return.
0___________
  • 60,014
  • 4
  • 34
  • 74
1

the huge difference is that in the first example the array only exist for the life of the containing function but in the second case it lives on until its released.

In your example there is only the main function so the difference doesnt matter, but in real applications it matters a lot.

Second there is a limit to how large the first one can be since its allocated on the stack which is a limited resource. (Try it, make the array 1 million elements). The second case is limited only by the size of the heap, which is usually much much larger

pm100
  • 48,078
  • 23
  • 82
  • 145
0

Ask these two questions "Will my array size fit in the stack ?" and "for how long do i need this array (program or function life time)?".

Statically allocated arrays exist for the life time of the function. when return, the function stack (and any variables declared local to that function including your array) are destroyed, and any attempt to access them gives an undefined behavior.

However, if you do need to return a pointer to your array so that the values you store are available back in the calling function, then you do need to dynamically allocate it, When you dynamically allocate memory with calloc the lifetime extends from the time the memory is allocated, until it is deallocated.

Keep in mind that statically allocated memory are faster and more efficient than a dynamically allocated one so if you don't really need it don't be fancy.

interesting
  • 149
  • 1
  • 10
0

Variable length arrays is conditionally supported by implementation.

If there is defined the macro name __STDC_NO_VLA__ then integer constant 1, intended to indicate that the implementation does not support variable length arrays or variably modified types.

Another problem is that the stack memory usually is much less than the memory used for dynamic memory allocation.

The size of a variable length array can be automatically changed then the control reaches anew the declaration of the array.

Variable length arrays have automatic storage duration and block scopes. So they are alive in block scopes where they are defined.

A dynamically allocated array can be resized using the function realloc preserving current values of its elements and you can explicitly control situations in the program when there is no enough space for a dynamically allocated array.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Generally speaking, only truly safe use of variable length arrays is for local typedef of multi-dimensional arrays. Anything else is dubious. Something like:

void *buf = calloc(a*b, sizeof(int));
typedef int Int2d[a][b];
Int2D *array2d = buf;
(*array2d)[y][x] = 42;

So use the calloc version. Only if you have a known small size, use VLA directly. And yes, that is a bit of a contradiction.

hyde
  • 60,639
  • 21
  • 115
  • 176