The strrchr function enables the caller to find the location of the last occurrence of a character in a string.

char *
strrchr(const char *s, int c);

The return value is a pointer to the found character, or NULL if it does not exist in the string.

Local Variables

We use a char search character for the same reason mentioned for strchr. Otherwise, we only need a pointer to the end of the string so we can search in the reverse direction.

const char  *cur    = NULL;
const char  search  = c;

Implementation

The implementation is similar to that of strrchr, but performed in the reverse direction. We use the beginning of the string as our terminal position, rather than that of the null-character. Another difference is that we first determine where the end of the string is, which we can rely on strlen to calculate for us.

The only catch to this function is that since the null-character is considered part of the search, we must ensure we compare that character every time - even if the string is empty (i.e. the string points to the null-character). This is where the --cur becomes important. When an empty string is searched, by pre-decrementing we ensure that we only inspect the null-character rather than looping an extra time (which would happen if post-decrement, cur--, was used).

if (!s)
{
    return NULL;
}

cur = s + strlen(s);
do
{
    if (search == *cur)
    {
        return (char *) cur;
    }

} while (--cur >= s);

return NULL;

Testing

First, we'll test our parameter validation by passing a NULL pointer, and attempting to search an empty string which should succeed when we search for the null-character. Next, we'll search for characters that don't exist at all, or exist past a null character in the array we define. Finally, make sure it works when finding characters at the beginning, middle, and end of the string (i.e. finding the null character), as well as finding the last occurrence of a character which occurs multiple times in the string.

int
strrchrTest(void)
{
    int     ret         = 1;
    char    str[]       = "ABCDEFGBCDEFG\0abcdefg";
    char    emptyStr[]  = "";

    do
    {
        /* NULL object */
        if (NULL != strrchr(NULL, 'a'))
        {
            break;
        }

        /* Search empty string for characters */
        if (NULL != strrchr(emptyStr, 'a'))
        {
            break;
        }

        /* Search empty string for the null-character */
        if (emptyStr != strrchr(emptyStr, '\0'))
        {
            break;
        }

        /* Search for non-existent character */
        if (NULL != strrchr(str, 'Z'))
        {
            break;
        }

        /* Search for char after null character */
        if (NULL != strrchr(str, 'a'))
        {
            break;
        }

        /* Valid search at beginning */
        if (str != strrchr(str, str[0]))
        {
            break;
        }

        /* Valid search in middle*/
        if (strchr(str + 2, str[1]) != strrchr(str, str[1]))
        {
            break;
        }

        /* Valid search at end */
        if ((str + strlen(str) - 1) != strrchr(str, str[strlen(str) - 1]))
        {
            break;
        }

        /* Search for null character at end */
        if ((str + strlen(str)) != strrchr(str, '\0'))
        {
            break;
        }

        ret = 0;
    } while (0);

    return ret;
}

Conclusion

strrchr is the reverse analogue of strchr with the same catch about finding the null-character.

char *
strrchr(const char *s, int c)
{
    const char  *cur    = NULL;
    const char  search  = c;

    if (!s)
    {
        return NULL;
    }

    cur = s + strlen(s);
    do
    {
        if (search == *cur)
        {
            return (char *) cur;
        }

    } while (--cur >= s);

    return NULL;
}
comments powered by Disqus