Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare ends of strings in C?

Tags:

c

string

People also ask

How do you check if you are at the end of a string in C?

The strrchr() function finds the last occurrence of c (converted to a character) in string . The ending null character is considered part of the string . The strrchr() function returns a pointer to the last occurrence of c in string . If the given character is not found, a NULL pointer is returned.

How do you determine the end of a string?

The end of the string is marked with a special character, the null character , which is simply the character with the value 0. (The null character has no relation except in name to the null pointer . In the ASCII character set, the null character is named NUL.)

Can I use == to compare strings in C?

You can't compare strings in C with ==, because the C compiler does not really have a clue about strings beyond a string-literal.


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.


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

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

  return( -1 );
}

Will return 0 if ending with ".foo".


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.


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.


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.