I'd like to suggest the following implementation:
// Find an instance of substr in an array of characters
// the array of characters does not have to be null terminated
// the search is limited to the first n characters in the array.
char *strnstr(char *str, const char *substr, size_t n)
{
char *p = str, *pEnd = str+n;
size_t substr_len = strlen(substr);
if(0 == substr_len)
return str; // the empty string is contained everywhere.
pEnd -= (substr_len - 1);
for(;p < pEnd; ++p)
{
if(0 == strncmp(p, substr, substr_len))
return p;
}
return NULL;
}
The rationale for the first parameter is not to be const is that you may want to use the return value pointer to modify the array in that location.
for completeness, in C++, it's possible to add an overloaded variant that's const:
const char *strnstr(const char *str, const char *substr, size_t n)
{
return strnstr((char *)str, substr, n);
}
Any comments?
As suggested, here's a test program:
#include <iostream>
#include <cstring>
#include <string>
int main()
{
char s[] = "1234567890abcdefgh";
size_t n = sizeof(s) - 1;
const char *patterns[] = { "efgh", "0ab", "0b", NULL };
const char *result = NULL;
const char *pPattern = patterns[0];
std::cout << "array of length " << n << " is: " << s << std::endl;
for (int i = 0; pPattern; pPattern = patterns[++i])
{
result = strnstr(s, pPattern, n);
std::cout << "finding " << pPattern << " n=" << n << ": "
<< (result ? result : "(null)") << std::endl;
}
pPattern = patterns[0];
result = strnstr(s, pPattern, n-1);
std::cout << "finding " << pPattern << " n=" << n-1 << ": "
<< (result ? result : "(null)") << std::endl;
return 0;
}
Output:
array of length 18 is: 1234567890abcdefgh
finding efgh n=18: efgh
finding 0ab n=18: 0abcdefgh
finding 0b n=18: (null)
finding efgh n=17: (null)