Implementing strnstr
How about:
char *strnstr(char *haystack, char *needle, size_t len) {
if (len == 0) return haystack; /* degenerate edge case */
while (haystack = strchr(haystack, needle[0])) {
if (!strncmp(haystack, needle, len)) return haystack;
haystack++; }
return 0;
}
If you want haystack
to not be null terminated, you'll need two length args:
char *memmem(char *haystack, size_t hlen, char *needle, size_t nlen) {
if (nlen == 0) return haystack; /* degenerate edge case */
if (hlen < nlen) return 0; /* another degenerate edge case */
char *hlimit = haystack + hlen - nlen + 1;
while (haystack = memchr(haystack, needle[0], hlimit-haystack)) {
if (!memcmp(haystack, needle, nlen)) return haystack;
haystack++; }
return 0;
}
which is available in GNU libc, though older versions are broken.
The implementation provided by Chris Dodd has the following disadvantages:
- It defeats the purpose of
strnstr
in that thewhile
condition uses the unbounded string functionstrchr
- It depends on
haystack
being NULL terminated, which is a deviation from the usual implementation ofstrnstr
, for example as provided by GNU-Darwin - The call to
strchr
is an unnecessary function call whenstrchar
is not inlined - Returns
haystack
instead ofNULL
whenlen
is zero, a deviation from the acceptedstrstr
semantics - Returns an empty string instead of
haystack
whenneedle
has length of zero
The following implementation remedies the above problems without becoming as difficult to read as the GNU-Darwin implementation, and is Creative Commons licensed:
#include <string.h>
char *strnstr(const char *haystack, const char *needle, size_t len)
{
int i;
size_t needle_len;
if (0 == (needle_len = strnlen(needle, len)))
return (char *)haystack;
for (i=0; i<=(int)(len-needle_len); i++)
{
if ((haystack[0] == needle[0]) &&
(0 == strncmp(haystack, needle, needle_len)))
return (char *)haystack;
haystack++;
}
return NULL;
}