Reputation: 55
Assume we have the following piece of code:
void foo() {
char buffer[100];
}
Is there a (preferably portable) way in C to deallocate buffer from the runtime stack (akin to add esp, 100 in assembly), before foo() returns?
Upvotes: 1
Views: 1337
Reputation: 51842
No. The best you can do in C is use scopes:
void foo()
{
{
char buffer[100];
}
}
and rely on the compiler to consider the 100 bytes of buffer
available again after the inner scope exits. Unfortunately, this is not guaranteed by the standard and you need to depend on the compiler. For example, consider the following program on a typical Linux machine with a stack space of 8192KB (ulimit -s
):
#include <stdio.h>
int main(void)
{
{
char buffer1[8192 * 800] = { 0 };
((char volatile *)buffer1)[0] = buffer1[0];
printf("%p\n", buffer1);
}
{
char buffer2[8192 * 800] = { 0 };
((char volatile *)buffer2)[0] = buffer2[0];
printf("%p\n", buffer2);
}
return 0;
}
(The weird cast is to prevent the buffer variables from being optimized out.)
The program will overflow the available stack space on some compilers when not building with optimizations. clang -O0
for example will crash, but clang -O1
will reuse the buffer1
memory for buffer2
and both addresses will be the same. In other words, buffer1
has been "freed" in a sense when the scope exits.
GCC on the other hand will do this optimization even at -O0
.
Upvotes: 5
Reputation: 67476
it is the automatic variable and you do not have to do anything as it will be reallocated when leaving the scope of it. in your case when you return from the function
if you want make the scope narrowed just place it inside another scope.
foo()
{
for(... .)
{
// if defined here it will be only in the for loop scope
}
{
// if defined here it will be only in this internal scope
}
}
bare in mind that it requires the C standard which allows it.
Upvotes: 1
Reputation: 84551
Because char buffer[100];
is declared local to the function stack for void foo()
, when void foo()
returns, the storage for buffer
is released for reuse and is no longer valid for access after that point.
So there is nothing you need to do, or can do, to "deallocate buffer" as that is handled automatically by virtue of buffer
being an array with automatic storage duration, e.g. see: C11 Standard - 6.2.4 Storage durations of objects (p5)
Upvotes: 1
Reputation: 263237
Given:
void foo(void) {
char buffer[100];
}
the lifetime of the object buffer
begins when execution reaches the opening {
(on entry to the function) and ends when execution leaves the block, reaching the closing }
(or by other means such as a goto
, break
, or return
statement).
There's no way to end the lifetime of buffer
other than by leaving the block. If you want to be able to deallocate it, you have to allocate it in some other way. For example, if you allocate an object by calling malloc()
, you can (and pretty much must) deallocate it by calling free
:
void foo(void) {
char *buffer_ptr = malloc(100);
if (buffer_ptr == NULL) /* error handling code here */
/* ... */
if (we_no_longer_need_the_buffer) {
free(buffer_ptr);
}
/* now buffer_ptr is a dangling pointer */
}
An alternative is to restrict the lifetime of buffer
by defining it in a nested block:
void foo(void) {
/* ... */
{
char buffer[100];
/* ... */
}
/* buffer's lifetime has ended */
}
But just because buffer
's lifetime ends when control leaves the inner block, that doesn't guarantee that it's physically deallocated. In the abstract machine, buffer
no longer exists after leaving the inner block, but the generated code might leave it on the stack just because it's more convenient.
If you want control over allocation and deallocation, you need to use malloc
and free
.
Upvotes: 2