DEV Community

Discussion on: Custom endsWith and startsWith Functions

Collapse
 
pauljlucas profile image
Paul J. Lucas

You should be passing char const* around; you should be using size_t, not int. Calculating strlen() in advance is more work that necessary: just iterate until you encounter the \0 byte at the end of the string (which is what strlen() does). You're also not checking for the cases where target is longer than string which means your code will likely core dump.

Here's a simpler (and correct) implementation of starts_with():

bool starts_with(char const *string, char const *target) {
  for ( ; *target != '\0' && *target == *string; ++target, ++string )
    ;
  return *target == '\0';
}
Enter fullscreen mode Exit fullscreen mode

I'll leave a simpler (and correct) implementation of ends_with() as an exercise for the reader.

Collapse
 
rivea0 profile image
Eda

Thank you for pointing these out. I only have a very basic understanding of C from a general introductory course, so I should've probably not even attempted writing about it in the article.

I guess ends_with() could also work like this:

bool ends_with(char const *string, char const *target) {
  size_t diff = strlen(string) - strlen(target);
  return strcmp(string + diff, target) == 0;
}
Enter fullscreen mode Exit fullscreen mode

But, I'm not sure how I could avoid using strlen() here, and do it in a similar way to your starts_with().

I'll update the article later on, and also would like to apologize for being quick to write a C example while still being quite the beginner, but, lesson learned. Thank you.

Collapse
 
pauljlucas profile image
Paul J. Lucas • Edited

size_t diff = strlen(string) - strlen(target);

Nope. size_t is an unsigned type. If target is longer than string, you'll end up with a very large positive number.

For ends_with(), the simplest solution does use strlen():

bool ends_with( char const *s, char const *t ) {
    size_t const s_len = strlen( s );
    size_t const t_len = strlen( t );
    return t_len <= s_len && strcmp( s + s_len - t_len, t ) == 0;
}
Enter fullscreen mode Exit fullscreen mode

However, that's slightly inefficient. If t_len is much longer than s_len, then you've wasted time traversing to the end of t. This version is more efficient:

bool ends_with( char const *s, char const *t ) {
    char const *const t0 = t;
    for ( ; *t != '\0'; ++s, ++t ) {
        if ( *s == '\0' )
            return false;
    }
    for ( ; *s != '\0'; ++s )
        ;
    size_t const t_len = (size_t)(t - t0);
    return strcmp( s - t_len, t0 ) == 0;
}
Enter fullscreen mode Exit fullscreen mode

You're determining t_len while checking to see if you've gone past the end of s: if you have, then s can't end with t and you can just stop immediately. After, you scan for the end of s. Once you find it, then finally check for a match.

Thread Thread
 
rivea0 profile image
Eda

The first example made perfect sense, but I struggle with for ( ; s[ t_len ] != '\0'; ++s ); line from the second one.

So, in the second version, with an example string being "hey" and target being "ey", t_len would be 2, if I understand it right. Since "ey" is not longer than "hey", we don't return false immediately. But, doesn't incrementing s until the length of target in the first for loop mean that s is now only at the last character "y". So, s[t_len] confused me.

Also, is s0 needed since it's not used here?

Sorry for asking noob questions, I'm surely missing a lot and confusing myself but trying to understand it, now even regret writing the example in the first place. Thank you for your time and patience.

Thread Thread
 
pauljlucas profile image
Paul J. Lucas

You are correct: s0 is not needed. (It was left over from an earlier version.) You've also found a bug. (Even "simple" code like this can be tricky!) I've edited the code with a corrected version.

Thread Thread
 
rivea0 profile image
Eda

Thank you, again, for your help. I updated the article with the correct versions.