How to compare ends of strings in C?

Solution 1:

Don't call strlen more than once per string.

int EndsWith(const char *str, const char *suffix)
{
    if (!str || !suffix)
        return 0;
    size_t lenstr = strlen(str);
    size_t lensuffix = strlen(suffix);
    if (lensuffix >  lenstr)
        return 0;
    return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}

int EndsWithFoo(const char *str) { return EndsWith(str, ".foo"); }

EDIT: added NULL check for the pedantic. For the ultra pedantic, debate whether it should return non-zero if both str and suffix are both NULL.

Solution 2:

int EndsWithFoo( char *string )
{
  string = strrchr(string, '.');

  if( string != NULL )
    return( strcmp(string, ".foo") );

  return( -1 );
}

Will return 0 if ending with ".foo".

Solution 3:

I don't have access to a compiler right now, so could someone tell me if this works?

#include <stdio.h>
#include <string.h>

int EndsWithFoo(const char* s);

int
main(void)
{
  printf("%d\n", EndsWithFoo("whatever.foo"));

  return 0;
}

int EndsWithFoo(const char* s)
{
  int ret = 0;

  if (s != NULL)
  {
    size_t size = strlen(s);

    if (size >= 4 &&
        s[size-4] == '.' &&
        s[size-3] == 'f' &&
        s[size-2] == 'o' &&
        s[size-1] == 'o')
    {
      ret = 1;
    }
  }

  return ret;
}

Anyway, be sure to qualify the parameter as const, it tells everyone (including the compiler) that you don't intend to modify the string.

Solution 4:

If you can change the signature of your function, then try changing it to

int EndsWith(char const * str, char const * suffix, int lenstr, int lensuf);

This will result in a safer, more reusable and more efficient code:

  1. The added const qualifiers will make sure you don't mistakenly alter the input strings. This function is a predicate, so I assume it is never meant to have side-effects.
  2. The suffix to compare against is passed in as a parameter, so you can save this function for later reuse with other suffixes.
  3. This signature will give you the opportunity to pass the lengths of the strings in if you already know them. We call this dynamic programming.

We can define the function like so:

int EndsWith(char const * str, char const * suffix, int lenstr, int lensuf)
{
    if( ! str && ! suffix ) return 1;
    if( ! str || ! suffix ) return 0;
    if( lenstr < 0 ) lenstr = strlen(str);
    if( lensuf < 0 ) lensuf = strlen(suffix);
    return strcmp(str + lenstr - lensuf, suffix) == 0;
}

The obvious counter-argument for the extra parameters is that they imply more noise in the code, or a less expressive code.

Solution 5:

The strlen(".foo")s are not required. If you really wanted to have it flexible you could use sizeof ".foo" - 1 -- a compile time constant.

Also, a null string check would be good.