You may be making this more complicated than need be. There is no reason to pass the address of (e.g. &allocated
) to your deallocate
function (except to set the value of the original pointer to NULL
without utilizing a return). You can simply pass a pointer. Yes, the function will receive a copy of that pointer, but it will still contain the starting address of the block of memory to be freed. e.g.:
void deallocate (void *ptr)
{
if (!ptr) return;
free (ptr);
}
If your intent was to deallocate and set the value pointed to by the original pointer to NULL
within your deallocate
function, then yes, you do need to pass the address of the original so that setting the pointer to NULL
is reflected back in the calling function (or you could make your function void *
and return a pointer to the value set to null). Leaving the parameter passed to deallocate
as a void
pointer, you could do the following:
void deallocate_doubleptr (void *ptr)
{
if (!ptr || !*(void **)ptr) return;
free (*(void **)ptr);
*(void **)ptr = NULL;
}
(note:, you do not pass a void **
parameter, you simply pass a void *
(void) pointer and cast as required within the function. The parameter is still a void
pointer.)
A short example illustrating the point that both are equivalent, except for the explicit assignment of NULL
, and guessing at what your allocate_array
would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *allocate_array (size_t size, size_t nmemb, int set);
void deallocate (void *ptr);
void deallocate_doubleptr (void *ptr);
int main (int argc, char **argv) {
size_t size = argc > 1 ? (size_t)strtoul (argv[1], NULL, 10) : 1;
size_t nmemb = argc > 2 ? (size_t)strtoul (argv[2], NULL, 10) : 128;
int set = argc > 3 ? (int)strtol (argv[3], NULL, 10) : 0;
char *str = "The quick brown fox jumps over a lazy dog.";
char *allocated = NULL;
if ((allocated = allocate_array (size, nmemb, set)))
printf ("\nsuccessfully allocated '%zu' bytes initialized to '%d' ('%c').\n",
size * nmemb, set, set);
if (31 < set && set < 127) { /* if filled with printable ASCII */
allocated[strlen (str)] = 0; /* nul-terminate */
printf ("allocated : '%s'\n", allocated); /* output array */
}
strncpy (allocated, str, size * nmemb - 1); /* copy str to array */
allocated[size * nmemb - 1] = 0; /* nul-terminate */
printf ("allocated : '%s'\n", allocated); /* output */
#ifdef DEALLOCDBL
deallocate_doubleptr (&allocated);
printf ("deallocated all memeory, pointer reinitialized to 'NULL'\n");
#else
deallocate (allocated);
printf ("deallocated all memeory.\n");
#endif
return 0;
}
void *allocate_array (size_t size, size_t nmemb, int set)
{
if (!size || !nmemb) {
fprintf (stderr, "error: invalid size or number of members.\n");
return NULL;
}
void *memptr = NULL;
if (set != 0) {
memptr = malloc (nmemb * size);
memset (memptr, set, nmemb * size);
}
else
memptr = calloc (nmemb, size);
if (!memptr) {
fprintf (stderr, "error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return memptr;
}
void deallocate (void *ptr)
{
if (!ptr) return;
free (ptr);
ptr = NULL;
}
void deallocate_doubleptr (void *ptr)
{
if (!ptr || !*(void **)ptr) return;
free (*(void **)ptr);
*(void **)ptr = NULL;
}
Compile
gcc -Wall -Wextra -o bin/allocate_deallocate allocate_deallocate.c
or
gcc -Wall -Wextra -DDEALLOCDBL -o bin/allocate_deallocate_dbl allocate_deallocate.c
(most compilers should take the same, or very similar options)
Output
The output is the same regardless of the implementation called. (e.g. allocate_deallocate
or allocate_deallocate_dbl
):
$ ./bin/allocate_deallocate 1 64 65
successfully allocated '64' bytes initialized to '65' ('A').
allocated : 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
allocated : 'The quick brown fox jumps over a lazy dog.'
deallocated all memeory.
Memory/Error Check
$ valgrind ./bin/allocate_deallocate 1 64 65
or
$ valgrind ./bin/allocate_deallocate_dbl 1 64 65
==13759== Memcheck, a memory error detector
==13759== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==13759== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==13759== Command: ./bin/allocate_deallocate
==13759==
successfully allocated '64' bytes initialized to '65' ('A').
allocated : 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
allocated : 'The quick brown fox jumps over a lazy dog.'
deallocated all memeory, pointer reinitialized to 'NULL'
==13759==
==13759== HEAP SUMMARY:
==13759== in use at exit: 0 bytes in 0 blocks
==13759== total heap usage: 1 allocs, 1 frees, 64 bytes allocated
==13759==
==13759== All heap blocks were freed -- no leaks are possible
==13759==
==13759== For counts of detected and suppressed errors, rerun with: -v
==13759== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Look it over and let me know if you have any questions.