The strnstr
function is not defined in the C Standard, it is available on BSD and some other systems as an extension.
Here is the man page on OS/X:
NAME
strstr
, strcasestr
, strnstr
-- locate a substring in a string
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <string.h>
[...]
char *strnstr(const char *haystack, const char *needle, size_t len);
[...]
DESCRIPTION
[...]
The strnstr()
function locates the first occurrence of the null-terminated string needle
in the string haystack
, where not more
than len
characters are searched. Characters that appear after a '\0'
character are not searched. Since the strnstr()
function
is a FreeBSD specific API, it should only be used when portability is not a concern.
RETURN VALUES
If needle
is an empty string, haystack
is returned; if needle
occurs nowhere in haystack
, NULL
is returned; otherwise a pointer
to the first character of the first occurrence of needle
is returned.
EXAMPLES
The following sets the pointer ptr
to the "Bar Baz"
portion of largestring
:
const char *largestring = "Foo Bar Baz";
const char *smallstring = "Bar";
char *ptr;
ptr = strstr(largestring, smallstring);
The following sets the pointer ptr
to NULL
, because only the first 4 characters of largestring
are searched:
const char *largestring = "Foo Bar Baz";
const char *smallstring = "Bar";
char *ptr;
ptr = strnstr(largestring, smallstring, 4);
This specification is not concise enough, (the man page for the linux kernel version is even more imprecise), yet the example on BSD systems (notably above here) is clear: len
is the maximum number of bytes to consider in haystack
, not needle
, which is just a regular null terminated C string.
Your function does not work for multiple reasons:
- the semantics are incorrect as you consider
length
to limit s2
instead of s1
- in your approach, duplicating
s1
is useless and counter-productive: result
, if non NULL
, will point into the allocated copy that is freed before returning from the function, hence accessing the string pointed to by the return value will have undefined behavior.
strncpy
does not null terminate the destination array if the source string has at least length
characters before its own null terminator. You must set ss2[length] = '\0';
for your approach to work, but again, the real strnstr()
function operates differently.
- using
malloc()
and free()
is probably not what you are expected to do, and failing to test for potential allocation failure is a mistake.
Here is a corrected version:
char *strnstr(const char *s1, const char *s2, size_t n) {
// simplistic algorithm with O(n2) worst case
size_t i, len;
char c = *s2;
if (c == '\0')
return (char *)s1;
for (len = strlen(s2); len <= n; n--, s1++) {
if (*s1 == c) {
for (i = 1;; i++) {
if (i == len)
return (char *)s1;
if (s1[i] != s2[i])
break;
}
}
}
return NULL;
}
strncpy
does not add a terminating zero. – Depopulatestrncpy(ss2, s2, length);
, addss2[length] = '\0';
to insuress2
is terminated. 2) note: returning pointer to a malloc'd variable. – Cellobiose