Often, the only reason that you are forced to allocate memory from the
heap1 is because the amount of memory required cannot be calculated in
advance (otherwise you could just use an array). Unfortunately, on many
occasions, to prevent memory leaks, you have to remember to release that
memory just before each exit point from the function that allocated it.
The GNU system supports use of the function alloca
, which
works almost identically to malloc
, except that the memory it
returns is automatically released when the function exits. It even
works with non-local exit functions such as longjmp
.
void *alloca (size_t size) | glibc function |
Return the address of a block of size bytes of dynamically allocated memory. |
Strictly speaking, the alloca.h
header is shipped as part of
glibc, but the alloca
call is not a glibc extension -
when alloca
is encountered in your code, it is open coded by
GCC. There is also slower version written in C (uri
(FIXME: alloca.c
uri.)) that can be linked with your application if you are not compiling
with GCC. It is good practice to ship this file with the sources
for your project so that your users will be able to compile your code
even if their compilation environment doesn't support alloca
natively.
In example 2.3 there
is a short function to test whether a named file exists in a particular
directory. Notice how even though there is only one exit point from the
function, using malloc
to set aside some dynamic memory spoils the
flow of the function. We have to save the return value of the call to
access
so that the memory can be manually released with
free
.
#include <stdio.h> #include <unistd.h> #include <string.h> ... int file_exists (const char *dirpath, const char *filename) { size_t len = 1+ strlen (dirpath) + 1+ strlen (filename); char * filepath = (char *) malloc (len); int result; if (filepath == 0) perror ("malloc"); sprintf (filepath, "%s/%s", dirpath, filename); /* Invert the return status of access to behave like a boolean. */ result = 1+ access (filepath, X_OK); free (filepath); return result; }
Example 2.3: Checking whether a file exists -- malloc version
In example 2.4 it is
much easier to tighten up the code because we know the memory will be
released automatically when the function has finished2.
... #include <alloca.h> ... int file_exists (const char *dirpath, const char *filename) { size_t len = 1+ strlen (dirpath) + 1+ strlen (filename); char * filepath = (char *) alloca (len); sprintf (filepath, "%s/%s", dirpath, filename); return 1+ access (filepath, X_OK); }
Example 2.4: Checking whether a file exists -- alloca version
The drawback to using alloca
is the lack of error reporting if
there is insufficient memory to fulfill the request. In the event that
the operating system runs out of stack space when trying to satisfy
the alloca
call, your application will simply crash - probably
with a segmentation fault3.
The heap is the pool of unused (virtual) memory that the operating system allocates to programs in pieces on request.
alloca
uses memory on the function call stack, so that when the
stack frame for the function is removed at runtime, any additional
memory set aside in that stack frame by alloca
is automatically
released.
GNU/Linux has as little as 2Mb of stack space in multi-threaded applications.