Is there a strchr with boundary?

Viewed 642

There is a char *strchr( const char *str, int ch ) function defined in <string.h>.

It has no boundary, after which it stops the search.

Is there a similar function somewhere, which you can pass a boundary to?

Edit:

I have a char* pos and a length of a substring and I want to find a specific ASCII character in it, but I don't want it to search up to the very null-terminator, because I don't care for the second part of the character sequence.

4 Answers

You can try:

void* memchr( const void* ptr, int ch, size_t count )

As the other answer points out, you can use memchr, but you'll need to call it twice if you want to avoid going out of bounds:

char *strnchr(const char *s, int c, size_t n)
{
    char *nul = memchr(s, 0, n);
    if(!c) return nul;
    if(nul) n = nul - s;
    return memchr(s, c, n); 
}

With the right hardware optimization, this may be more efficient than just checking the first n characters:

char *strnchr(const char *s, int c, size_t n)
{
     for(char *p = s; (p - s) < n; p++) {
         if(*p == c) return p;
         if(!*p) break;
     }
     return NULL;
}

You can of course just call strchr and compare the result against the desired bound.

char *strnchr(const char *s, int c, size_t n)
{
    char *p = strchr(s, c);
    if (p && (p-s) < n)
        return p;
    else
        return NULL;
}

This does mean that if the string is much longer than n characters, and the desired character c is not found in the first n, then the call to strchr may go on to search the whole rest of the string, wasting time. Mad Physicist's answer avoids this, but at the cost of either making two passes over the string, or writing your own loop which may not take advantage of highly optimized library string functions.

Is there a strchr with boundary?

There is not a standard library solution that mimics strchr() with a size limit.

Easy enough to code one though.

Loop termination

To form a strnchr(const char* ptr, int ch, size_t size) obliges a loop to stop on one of 3 cases:

  • Match found (*ptr == ch)

  • Null character found (*ptr == '\0')

  • Iteration meets size.

Common mistakes:

  • Compare using ch and not the correct (char) ch.

  • Special consideration when ch == 0. strchr(s, 0) returns a pointer to the null character.

  • Special consideration when size == 0. A return of NULL is expected, not UB.

  • Using int size and not size_t.

  • Using char *ptr and not const char *ptr.

Direct implementation:

char *strnchr(const char* ptr, int ch, size_t size) {
  while (size > 0) {
    size--;
    if (*ptr == (char) ch) {
      return ptr;
    } 
    if (*ptr == '\0') {
      break;
    } 
    ptr++;
  }
  return NULL;
}

Efficiency

Let len = length of string (unbounded if not exist), m = match offset (unbounded if not exist),

This solution is O(min(len, m, size)). Other posted solutions are are O(min(m, max(len, size)), O(min(len, m, size)), O(min(len, m) with UB), O(min(m, size) with UB).

Get correct functionality first, then optimize.

I'll leave optimization ideas for others.


Reference: strchr()

The strchr function locates the first occurrence of c (converted to a char) in the string pointed to by s. The terminating null character is considered to be part of the string.

The strchr function returns a pointer to the located character, or a null pointer if the character does not occur in the string.

Related