Why do we not declare arrays with variable size? - c

My supervisor saw something in my C code similar to:
size = f(some parameters);
int array[size];
He said that it is preferable to allocate such arrays with malloc. His description was something like:
Allocating it on the stack like that requires that your stack remains valid for the entire run-time of the program.
I had no clue what he meant, so this is just as close as I remember to his wording by the end of the meeting, without knowing the actual meaning. What did he mean? (alternatively, maybe someone can explain another reason not to declare arrays in such manner).

Any variable declared local will be only valid during the execution of the function, as it will be allocated in stack
If you need this array outside the function where it was declared you need to allocate it with malloc, but if you are using it only inside this function and during this execution is okay
Just mind that any local variables will use stack memory, so be sure that your array will never be big enough to cause a stack overflow in your program!

There's nothing wrong with using variable length arrays in c99 in general. The array will live in the scope it is declared in, just like any other variable. This is something you should always have in mind, so of course, if you declare the VLA in a function and attempt to return a pointer to it, this is an error (it doesn't exist any more once you leave the function).
Reasons not to use VLAs:
If you need the array even after returning from the function that creates it, of course you can't use it, as explained above, but this is true for any object with automatic storage
Stack space is somewhat limited, so if your array will be really big, it's better to dynamically allocate it.
c11 makes VLAs optional. So your code using VLAs might not work any more on a standard-compliant C11 compiler.

Related

Dynamically allocating array with the [] operator instead of using malloc?

I am sure this has been asked a million times but I couldn't find an answer that explained it. I have been told to never do this but I haven't really understood why. Why doesn't something like this count as dynamically allocating memory and why is it that bad?
int a;
scanf("%d",&a);
int arr[a];
This is not dynamic allocation but a variable length array.
The lifetime of such an array is its enclosing scope, just like an array with a fixed size, so you don't need to worry about deallocation. These arrays typically reside on the stack, so the size of the stack does put limitations on how big a VLA (or any array) can be.
If you find that a VLA is too big for the stack, you can always fall back to using malloc.
Dynamically allocating array with the [] operator instead of using malloc?
The [] here is used to define an array. [] here, is not an operator.
int arr[a];
I have been told to never do this but i havent really understood why.
This mantra applies to many things in C (and life), do not use until you understand how to use it.
Why doesnt something like this count as dynamically allocating memory
It is dynamically allocating memory allocation, but usually uses a different memory pool and has a different lifetime than via malloc().
... and why is it that bad?
int arr[a]; is a variable length array (VLA) and has the following issues:
Not always available. VLAs supported in C99 and often, but not always, in later versions. Research __STDC_NO_VLA__.
With int a, code is undefined behavior (UB) when a <= 0.
When a is too large, there is no standard mechanism to detect insufficient memory.
VLA better used in controlled smaller size cases.
First of all, let me tell you that this is called variable length array, and it's an optional feature. Better not to rely on this feature (or compiler support).
On the other hand, allocator functions (malloc(), free() and family) are standard compliant and any conforming compiler / library will support these functions.
That said, the differences are mentioned in other answers, primary differences are with scope and portability.
Why doesnt something like this count as dynamically allocating memory
That the size of the object is determined at runtime is not sufficient for dynamic allocation. Dynamic allocation requires direct or indirect use of one of the functions that specifically performs dynamic memory allocation, with malloc, calloc, and realloc being the main examples. Your example ...
int arr[a];
... does not do this, so the object is not dynamically allocated. You arr is a more-or-less ordinary local variable with variable-length array type.
Semantically, dynamically allocated objects have "allocated" storage duration, which means that they exist and retain their last-stored value until explicitly deallocated. Your arr instead has "automatic" storage duration, which means that it ceases to exist when execution of its innermost containing block terminates.
and why is it that bad?
Opinions vary. VLAs were a required feature in C99, but support was made optional in C11. If you use VLAs in your code, then, you limit its portability. C++ does not support them (or at least did not -- I understand that they are now coming to C++, too, and maybe they have already arrived), which may be an issue for some.
However, the main risk cited is that the usual and natural implementation of VLAs is to allocate them on the stack, and stack size is typically a lot more limited than heap space. In a naive example such as yours, it is easy to create a stack overflow, and this may depend on user input, thus making it both difficult to test and a potential security risk.
I do use VLAs in my code from time to time, but usually in ways that are not subject to the stack-busting risk described above. I generally look skeptically on admonitions to "never do that", but indeed I would never write the exact code you present for a production application.
This is an example of a variable length array. Its lifetime is the same as any other auto variable (including fixed-length arrays), so memory for it will be released once you exit its enclosing scope.
Unlike fixed-length arrays, VLAs cannot be declared at file scope (outside of any function) or with the static keyword, nor can they be declared with an initializer. Because of how they are typically managed, they cannot be arbitrarily large. Despite the name, they cannot be resized once they are defined - the "variable" in variable length only means that their size can be different each time they are defined.
VLAs are useful but limited. They're great when you need some temporary working storage that's local to a function and doesn't need to be too big (not much bigger than a megabyte or so).
They were only introduced in C99 and made optional in C11, so support for them may be a little spotty.

Assert the allocation of a variable-length array

I apologize for the possible duplicate (have not been able to find an answer to that):
Do we need to ensure that the allocation of a variable-length array has completed successfully?
For example:
void func(int size)
{
int arr[size];
if (arr == NULL)
{
// Exit with a failure
}
else
{
// Continue as planned
}
}
It seems obvious that the answer is yes, but the syntax arr == NULL feels a bit unusual.
Thanks
UPDATE:
I admit to the fact that I haven't made sure that the code above even compiles (assuming that it does).
If it doesn't compile, then it means that there is no way to assert the allocation of a variable-length array.
Hence, I assume that if the allocation fails, then the program crashes immediately.
This would be a very awkward case, as it makes sense for a program to crash after an illegal memory access (read or write), but not after a non-successful memory allocation.
Or perhaps the allocation will not cause anything, but as soon as I access the array at an entry which "falls" outside the stack, I might get a memory access violation (as in a stack-overflow)...?
To be honest, I can't even see how VLAs are allocated on the stack if any more local variables follow them (other VLAs in particular), so I would appreciate an answer on that issue as well.
This question proceeds from a slightly flawed first premise. You cannot check if an array is NULL because, as is a popular discussion topic, an array is not a pointer in C. An array is the storage object, in-place.
You cannot get to code where the array name is accessible without the array having been allocated. A local array is exactly the same as any other local variable: its existence is inherent and assumed for the surrounding code to be running at all, and there's no notion in the language for checking whether any given variable slot has been "allocated" at all (as the comments on the question note, "the stack" is a notion below the level C operates on - the language assumes it "happens", by unspecified magic). It has to assume this much always succeeds in order for the code to make sense on a most basic level.
What happens in the case where the array couldn't be allocated is therefore the same as whatever happens when the runtime can't allocate space for any other local variable - the situation is inherently undefined and undefinable, because an assumption made by the C language abstract machine was violated. The language has no (fully formal) concepts that can even express this, let alone check for it or recover from it, so testing for it is similarly out of scope. Like a stack overflow, this is basically guaranteed to lead to a fatal crash.
This does not make VLAs useless, for several reasons:
Many uses of VLAs aren't going to be life-threateningly huge. Perhaps the only use of the variation is to choose a number between 3 and 5? This is no worse for space than using a few more scalar locals.
Just as avoiding infinite recursion requires the programmer to prove certain properties that a C compiler doesn't, similarly you should design your program with at least a weak bound on the amount of space VLAs will be allowed to consume at any given time. For instance, you can prove to yourself that no VLA functions are ever recursive, or called from a recursive function, and none of them use more than e.g. 10K space - that's plenty useful and should be safe.
You can view VLAs as an optimisation to allow you to save space where you otherwise would have had to allocate a statically-sized local array (e.g. in the first example, always allocating 5 instead of 3). As long as you know, and design around, the static upper bound, they are effectively guaranteed to make your program safer from overflow, by providing an option to not always use as much space when it isn't required.

ANSI C, Garbage Collector and Function enviroment Arrays, Exiting the function will cancel the array?

I need to code a function in which i declare a new array and then i need that array to stay in the memory...
I was wondering which is the best programming practice to attain this result, and i would also love to understand how does the garbage collector work in this specific situation
More in the case, if i declare a function and inside it i inizializate an array, if i keep the reference to the address outside the function, Once the function as finished working, and it's enviroment cease to exist, will the Array still be usable, or do i risk that further malloc or array declaration would unexpectdly override my previuos array?
also, if i use a malloc inside a function, will the memory allocated stay reserved untill i free it no matter where i do use the malloc?
Thanks for the help anyone will offer.
There is no garbage collection in C!
You should read a book about C: The Definitive C Book Guide and List, specifically about pointers, the heap and the stack.
If you malloc a section of memory, the pointers live on the heap, and will not disappear or "become unusable" until free is called on that pointer. It has nothing to do with the scope of a function, which is also called a stack frame. If you declared an array of a fixed size on the stack then it would go out of scope once that stack unwinds.
In short, your last sentence is correct, if you use malloc, the memory will be allocated on the heap until you call free.

C Array Instantiation - Stack or Heap Allocation?

I guarantee that this question has been asked before, but I haven't been able to find it via search; sorry in advance for any redundancies.
It's my (potentially wrong) understanding that you only allocate to the stack when you know the size of an object at compile time. So in the case of initializing an array, you could do one of these (and this should go on the stack):
char charArray[50];
Since the size of this array is known at compile time, this should have no issues.
On the other hand, this (I believe) is also valid code:
char anotherCharArray[someVariable + 50];
Would this go on the stack as well? I am pretty sure the code segfaults if you free() this, so it makes me think it does, but it doesn't really make sense to me. Similarly, is the 100% sole situation where you have to use free() when the data was allocated via malloc?
Thanks in advance for your help.
If char charArray[50]; is defined at file scope (outside of all functions) or is static, it's not going to be on the stack, it's going to be a global preallocated at program's start variable. If it's not static and is defined at function scope, it's going to be on the stack.
char anotherCharArray[someVariable + 50]; can only be defined at function scope and is going to be on the stack.
All of the above applies to typical implementations of C. Atypical ones may use the heap instead of the stack and instead of the preallocated space in the data section of the program.
You don't free() what hasn't been allocated with malloc(), calloc() or realloc(). Simple. Some functions may imply the use of one of the above, e.g. POSIX strdup().
Similarly, is the 100% sole situation where you have to use free() when the data was allocated via malloc?
Yes. (Apart from calloc and realloc, their return value is also to be free()'d. Similarly, there are functions that use malloc() and this fact is documented, for example strdup() - the return value of these functions is also to be freed using free(), obviously.)
char anotherCharArray[someVariable + 50];
Would this go on the stack as well?
Yes, it does (in most implementations - of course, it's not always true that you assume, but on most of the platforms, it is). And yes this is valid code, but it is only standard in C99.

C function: is this dynamic allocation? initializating an array with a changing length

Suppose I have a C function:
void myFunction(..., int nObs){
int myVec[nObs] ;
...
}
Is myVec being dynamically allocated? nObs is not constant whenever myFunction is called. I ask because I am currently programming with this habit, and a friend was having errors with his program where the culprit is he didn't dynamically allocate his arrays. I want to know whether my habit of programming (initializing like in the above example) is a safe habit.
Thanks.
To answer your question, it's not considered dynamic allocation because it's in the stack. Before this was allowed, you could on some platforms simulate the same variable length allocation on the stack with a function alloca, but that was not portable. This is (if you program for C99).
It's compiler-dependent. I know it's ok with gcc, but I don't think the C89 spec allows it. I'm not sure about newer C specs, like C99. Best bet for portability is not to use it.
It is known as a "variable length array". It is dynamic in the sense that its size is determined at run-time and can change from call to call, but it has auto storage class like any other local variable. I'd avoid using the term "dynamic allocation" for this, since it would only serve to confuse.
The term "dynamic allocation" is normally used for memory and objects allocated from the heap and whose lifetime are determined by the programmer (by new/delete, malloc/free), rather than the object's scope. Variable length arrays are allocated and destroyed automatically as they come in and out of scope like any other local variable with auto storage class.
Variable length arrays are not universally supported by compilers; particularly VC++ does not support C99 (and therefore variable length arrays), and there are no plans to do so. Neither does C++ currently support them.
With respect to it being a "safe habit", apart from the portability issue, there is the obvious potential to overflow the stack should nObs be sufficiently large a value. You could to some extent protect against this by making nObs a smaller integer type uint8_t or uint16_t for example, but it is not a very flexible solution, and makes bold assumptions about the size of the stack, and objects being allocated. An assert(nObs < MAX_OBS) might be advisable, but at that point the stack may already have overflowed (this may be OK though since an assert() causes termination in any case).
[edit]
Using variable length arrays is probably okay if the size is either not externally determined as in your example.
[/edit]
On the whole, the portability and the stack safety issues would suggest that variable length arrays are best avoided IMO.

Resources