Can alloca() memory be reallocated?
No: that wouldn't work with a stack as commonly implemented. A variable on the stack occupies a fixed range of addresses. The next variable comes immediately after it, so there's no room to grow. Consider a function like this:
void f(int x) {
int i;
float *a = alloca(40 * sizeof(float));
int k;
…
}
The stack after the function prologue looks something like this:
----------------+-----+-----+-----+-------------------+-----+---------------------
... | ret | x | i | a | k | ...
----------------+-----+-----+-----+-------------------+-----+---------------------
^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
previous frames f's frame free space at the top
There's no room to grow a
.
I'm showing a highly simplified example: in the real world, variables end up in registers, variables can be reordered even if they do end up on the stack, etc. But only one variable can be the last one on the stack with room to grow.
So if realloca
existed, it could only be applied to the variable that's at the top of the stack. (Or else it would have to move everything else that's on top of it, but that would require updating all existing pointers to those, which is not possible in general.) This would be a very limited mechanism, so support for this feature would have a very small benefit. Supporting it would have a significant cost, because compilers are normally free to put things on the stack in the order they want: this feature would require a new mechanism to let the compiler know that one specific variable must go to the top.
It's possible that some C implementation somewhere has realloca
, but it's unlikely given the cost/benefit ratio.
Of course realloca
can easily be implemented if alloca
does not use a stack allocation strategy. But allocating on the stack is the whole point of alloca
. If you want resizable objects, you need a memory management structure with a heap interface, and that's what malloc
is for.
As a practical matter, there are several possible approaches to dynamic memory management in a library.
The most common approach is to call malloc
, realloc
and free
when you need them. That's what they're for.
In some environments, it's useful to support custom allocators. You can give the user of the library the option to pass pointers to alternative implementations of malloc
, realloc
and free
. It's useful when you want to write a portable library that needs to be used by code that is itself fully portable. Most of the time, though, users who want to use custom allocators can do it by linking their own malloc
and friends. And even that is rarely useful.
If you need code that can work in an environment without dynamic allocation (such as safety-critical environments), then you should not use alloca
either. alloca
is worse than malloc
because it causes unpredictable stack usage and can lead to a stack overflow which won't be detected at all, or which will only be detected by a program crash. If you need a variable (or large) amount of temporary memory in a function, have the user pass a suitably-sized buffer to you.
/** [documentation of the function] …
* working_buffer must point to an array of floats of 3*n elements.
*/
void f(size_t n, float *working_buffer);
Better, if you have the code size budget, pass the array size and verify it.
/** [documentation of the function] …
* working_buffer must point to an array of floats of 3*n elements.
*/
int f(size_t n, float *working_buffer, size_t working_buffer_length)
{
if (working_buffer_length < 3 * n) return -EINVAL;
…
}
The accepted answer has correctly pointed out that usually there is not enough benefit from realloca
because allocations are difficult to "grow".
Another issue I see is that these allocations have a life time till the end of the function. What happens when you pass this pointer to another function and call realloca
on it there? This function would not be able to change the stack frame of a function deeper on the stack. It also cannot reallocate it in its own frame because the object would be destroyed when it returns, whereas the original object would still have to be alive.
This problem is not there for malloc/realloc
because the heap has a global lifetime.
One could argue that the semantics can be defined in such way that a function can be realloced only in the function it was alloc
'd in. This greatly reduces the use such a function would have.