The loop for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);
has an empty body ;
which can also be written:
for (j = 0; s2[j] && s2[j] == s1[i + j]; j++) {
/* empty */
}
or
for (j = 0; s2[j] && s2[j] == s1[i + j]; j++)
continue;
It computes the length of the initial substring of s2
that matches characters at offsets i
and subsequent of s1
. At the end of the loop, j
is the number of matching characters up to but not including the null terminator.
It this initial substring is the full string s2
, which can be tested by comparing s2[j]
to the null terminator '\0'
, we have a match at position i
, hence if (!s2[j]) return i;
Note that this function returns 0
for an empty substring s2
, except if s1
is also empty, which is somewhat inconsistent. It should either return 0
in all cases:
int position(const char *s1, const char *s2) {
int i, j;
for (i = 0;; i++) {
for (j = 0; s2[j] && s2[j] == s1[i + j]; j++)
continue;
if (!s2[j]) return i;
if (!s1[i]) return -1;
}
}
Note also that this function may have undefined behavior if s1
is longer than INT_MAX
, which is possible on 64-bit systems where int
has 32 bits and pointers and object sizes have 64 bits. It would be safer to change the int
variable and return types to ptrdiff_t
defined in <stddef.h>
, albeit not full sufficient.
The standard function strstr
does not have these shortcomings as it is defined as returning a pointer to the match:
char *strstr(const char *s1, const char *s2);
Note however that in C, it returns a non const
pointer even if passed a const
pointer, potentially breaking const
correctness.
Here is a simplistic implementation using the same algorithm:
#include <string.h>
char *strstr(const char *s1, const char *s2) {
size_t i, j;
for (i = 0;; i++) {
for (j = 0; s2[j] && s2[j] == s1[i + j]; j++)
continue;
if (!s2[j]) return (char *)&s1[i];
if (!s1[i]) return NULL;
}
}
Good C libraries use more sophisticated algorithms, which I encourage you to search and study.