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;
}
comments powered by Disqus