For one reason or another, I want to hand-roll a zeroing version of malloc()
. To minimize algorithmic complexity, I want to write:
void * my_calloc(size_t size)
{
return memset(malloc(size), 0, size);
}
Is this well-defined when size == 0
? It is fine to call malloc()
with a zero size, but that allows it to return a null pointer. Will the subsequent invocation of memset
be OK, or is this undefined behaviour and I need to add a conditional if (size)
?
I would very much want to avoid redundant conditional checks!
Assume for the moment that malloc()
doesn't fail. In reality there'll be a hand-rolled version of malloc()
there, too, which will terminate on failure.
Something like this:
void * my_malloc(size_t size)
{
void * const p = malloc(size);
if (p || 0 == size) return p;
terminate();
}
AFAIK memset isn't required to check for NULL, so if the malloc fails you'll zero size bytes starting from address 0.
A null pointer has a reserved value that is called a null pointer constant for indicating that the pointer does not point to any valid object or function. You can use null pointers in the following cases: Initialize pointers. Represent conditions such as the end of a list of unknown length.
It is safe to free a null pointer. The C Standard specifies that free(NULL) has no effect: The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs.
The C and C++ languages have a null character (NUL), a null pointer (NULL), and a null statement (just a semicolon (;)). The C NUL is a single character that compares equal to 0. The C NULL is a special reserved pointer value that does not point to any valid data object.
Here is the glibc declaration:
extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
The __nonnull
shows that it expects the pointer to be non-null.
Here's what the C99 standard says about this:
If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined.
memset()
is in string.h
)Where an argument declared as
size_t n
specifies the length of the array for a function,n
can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4.
The
memset
function copies the value ofc
(converted to anunsigned char
) into each of the firstn
characters of the object pointed to bys
.
So strictly speaking, since the standard specifies that s
must point to an object, passing in a null pointer would be UB. Add the check (the cost compared to the malloc()
will be vanishingly small). On the other hand, if you know the malloc()
cannot fail (because you have a custom one that terminates), then obviously you don't need to perform the check before calling memset()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With