Reputation: 16013
In a C book I found in an example for implementing a dynamically resizing array this code (simplified):
void *contents = realloc(array->contents, array->max * sizeof(void *));
array->contents = contents;
memset(array->contents + old_max, 0, array->expand_rate + 1);
Source: Learn C The Hard Way – Chapter 34
I was a bit surprised what memset
is supposed to achieve here, but then I understood it's used in order to "zero out" the reallocated memory.
I googled in order to find out, if this is what I'm supposed to do after a realloc
and found a stackoverflow answer regarding this:
There is probably no need to do the
memset
[…]But, even if you wanted to "zero it out so everything is nice", or really need the new pointers to be
NULL
: the C standard doesn't guarantee that all-bits-zero is the null pointer constant (i.e.,NULL
), somemset()
isn't the right solution anyway.
Source: How to zero out new memory after realloc
The suggested solution instead of memset
is then to use a for
loop in order to set the memory to NULL
.
So my question is, as memset
does not necessarily mean setting values to NULL
and the for
loop solution seems a bit tedious – is it really needed to set the newly allocated memory?
Upvotes: 2
Views: 1936
Reputation: 1
This is wrong:
But, even if you wanted to "zero it out so everything is nice", or really need the new pointers to be NULL: the C standard doesn't guarantee that all-bits-zero is the null pointer constant (i.e., NULL), so memset() isn't the right solution anyway.
The C standard does in fact guarantee exactly that.
Per section 6.3.2.3 of the C standard:
An integer constant expression with the value 0, or such an expression cast to type
void *
, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.
Note that a pointer with a value of zero is a null pointer. That doesn't mean NULL
itself has to be zero. But also note that "any two null pointers shall compare equal". So any null pointer is equal to the NULL
value.
Since memset()
takes as its second argument an integer value, passing a zero integer value to memset()
will produce null pointers. Because the value passed to memset()
is "[a]n integer constant expression with the value 0", per 6.3.2.3.
Upvotes: 0
Reputation: 28674
So my question is, as memset does not necessarily mean setting values to NULL and the for loop solution seems a bit tedious – is it really needed to set the newly allocated memory?
realloc
doesn't initialize values of the newly allocated memory segment.
So it is needed to initialize the memory if you are planning to read values of that (uninitialized) memory. Because reading values from that uninitialized memory will trigger undefined behaviour.
By the way, safe way to use realloc
(since it can fail) is:
// Since using realloc with size of 0 is tricky and useless probably
// we use below check (from discussion with @chux)
if (new_size == 0)
dosmth();
else
{
new_p = realloc(p, new_size);
if (new_p == NULL)
{
// ...handle error
}else
{
p = new_p;
}
}
Upvotes: 4
Reputation: 154335
Setting a void *
to 0 is a value that will compare equal to NULL
. Likely memset(ptr, 0, size)
is OK - but need to see more code for certainty.
OTOH: is the code correct? Maybe should be
// memset(array->contents + old_max, 0, array->expand_rate + 1);
memset(array->contents + old_max, 0, sizeof(void *) * (array->expand_rate + 1) );
Upvotes: 0