memset
Writing a single value to a region of memory is most often used to initialize a
structure on the stack or the memory returned from a call to malloc
. It can
also be used to mark a region "dirty" with a predetermined value that can later
be searched for. The memset
function is used to perform such tasks
void *
memset(void *s, int c, size_t n);
And returns the value of the passed in pointer, s
.
Local Variables
Since data cannot be written by directly dereferencing a void *
, we need to
convert that to a pointer type we can use. The Standard specifies that the value
c
is to be converted to an unsigned char
when written, so an unsigned char
*
makes sense as our working pointer.
unsigned char *pChar = s;
Parameter Validation
We need to verify that a valid pointer is passed and also that the amount of
characters being set will not wrap around memory. We could return here if n
is
zero but that's an unlikely scenario. Rather than add a check to every call of
memset
, we'll let the least likely case suffer a few extra lines of code.
if ( !s ||
/* Check for wrapping */
((((unsigned long) -1) - ((unsigned long) s)) < n))
{
return s;
}
Implementation
The main portion of the loops looks similar to that of the working loops in
memmove
. We iterate and decrement n
, each time writing c
into the pointed
to character and finally increment the pointer by one character. Once finished,
we return the value of s
.
while (0 < n--)
{
*(pChar++) = (unsigned char) c;
}
return s;
Testing
Parameter validation aside, we need to verify that requesting zero characters be set is honored and that we can't set more characters than are left in memory. We also need to set some memory and verify that only the requested region was changed.
int
memsetTest(void)
{
int ret = 1;
char reg1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
char reg2[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
char reg3[] = "ABCD55555JKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
do
{
/* We may crash */
memset(NULL, 0, 10);
/* Request a set that would wrap, may crash */
memset((void *) ((unsigned long) -5), 0, 10);
/* No change should be made */
memset(reg1 + 4, 0, 0);
if (0 != (memcmp(reg1, reg2, sizeof(reg1))))
{
break;
}
/* Verify change in only the specified area */
memset(reg1 + 4, '5', 5);
if (0 != (memcmp(reg1, reg3, sizeof(reg1))))
{
break;
}
ret = 0;
} while (0);
return ret;
}
Conclusion
memset
provides a straightforward way to write a single value to every
character in a given region.
void *
memset(void *s, int c, size_t n)
{
unsigned char *pChar = s;
if ( !s ||
/* Check for wrapping */
((((unsigned long) -1) - ((unsigned long) s)) < n))
{
return s;
}
while (0 < n--)
{
*(pChar++) = (unsigned char) c;
}
return s;
}