1

I have an integer array that's only useful in a single code block. I'd like to declare it and initialise it to zero on the stack to avoid the overhead of the heap.

I'd like to do this dynamically and initialise every index to zero. Basically, I'd like a stack version of calloc!

Is this possible?

Connor
  • 867
  • 7
  • 18
  • 3
    If it's a fixed size you can initialise it to all `0` with, say `int array[8] = { 0 };` but with a variable length array you need to use `memset`. – Weather Vane Mar 10 '23 at 09:59
  • @Jabberwocky What if the array is very large? At what point is it better to allocate to the heap? – Connor Mar 10 '23 at 10:02
  • 4
    @Connor The definition of "large" is very system-specific. On a limited 8 bit microcontroller, 100 bytes of stack allocation is huge and a massive design mistake, whereas on an x86 PC it is nothing. – Lundin Mar 10 '23 at 10:10

3 Answers3

2

Variable length arrays (VLA) are typically allocated on the stack. However, as they have their size decided in run-time, you cannot provide an initializer to them. This could be solved with a separate call to memset.

void func (size_t n)
{
  int array[n];
  memset(array, 0, sizeof(array));
  ...
}

However, declaring arrays like this on the stack isn't really recommended practice in many situations. You'll have to ensure that the size is within some reasonable limits or you'll get stack overflow. calloc() + free() at the end is slower but safer in that regard.

Yet another option is static storage duration:

void func (size_t n)
{
  static int array[MAX];
  memset(array, 0, sizeof(int[n]));
  ...
  /* only use up to n items of the array */
}

This has the advantage of being fast and safe from stack overflows both. The disadvantages is that you have to pre-allocate the whole array, as well as thread safety concerns.

But please note that no matter which method you pick, you will reasonably have to design the code to work up to a "MAX" limit. Since a computer with unlimited memory will never exist. So it isn't correct to say that the static version consumes extra memory needlessly - it consumes enough memory to handle the worst-case scenario of your application. A stack or heap version which need to handle the same scenario will have to consume just as much memory under the worst-case scenario, though in that case only during a limited time.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • The last one is very dangerous - for example is not reentrant. I would not recommend doing it – 0___________ Mar 10 '23 at 10:10
  • 2
    @0___________ I already mentioned as much in the answer. It is not dangerous at all in a single core, single threaded system. In general I would probably say that stack overflow is a much more common bug than race condition bugs. Both are a pain in the neck to track down. You can however use a `static` array with mutex and be _thread-safe_, just not _reentrant_, with the subtle difference between those terms. – Lundin Mar 10 '23 at 10:11
  • It is exactly how bad code is written. static automatic variables are very dangerous and error-prone guys. Half of the standard library is almost useless because of it. – 0___________ Mar 10 '23 at 10:19
  • @0___________ Well that advise is kind of like "hey you cannot bring that that food because it attracts Bengal tigers". Well, what if I have no intention of traveling to some Indian jungle bringing this food item? "It is really dangerous if the tiger smells it!" "Well, I'm designing a kitchen for a polar expedition..." "No! Very bad practice to keep that item in your polar expedition kitchen, beware of the tigers!" – Lundin Mar 10 '23 at 10:48
  • Also I have no idea what a "static automatic variable" is. Sounds like a Polar Tiger... – Lundin Mar 10 '23 at 10:50
  • Lundin, I will leave it without commenting ...... – 0___________ Mar 10 '23 at 11:02
1

Some C | C++ compilers don't allow variable length arrays. Instead, arrays can be allocated from the stack using alloca() or _alloca(), depending on the compiler:

https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/alloca?view=msvc-170

Since there isn't something like calloca(), you'll need to zero the array allocated by alloca() in your code. You could create a define macro to do this.

rcgldr
  • 27,407
  • 3
  • 36
  • 61
  • Would you say learn.microsoft is a good reference for the C language? – Connor Mar 10 '23 at 20:36
  • 1
    @Connor - link to a [summary](https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-170) from Microsoft about features included or not included in it's C++ | C compilers. Most of my current C++| C programs are console programs built using Visual Studio. – rcgldr Mar 10 '23 at 20:51
0
  1. fixed size arrays
int foo(void)
{
   int arr[10] = {0,};  // it will zero the whole array
}
  1. VLAs
int bar(size_t size)
{
    int arr[size];
    memset(arr, 0, sizeof(arr));
}

or you can have macro to hide it from the view

#define ZEROARR(type, name, size) type name[size]; memset(&name, 0, sizeof(name))

int foo(size_t x)
{
    ZEROARR(int, arr, x);
}
0___________
  • 60,014
  • 4
  • 34
  • 74