Home > Software engineering >  Make own strchr() function but case-insensitive
Make own strchr() function but case-insensitive

Time:05-04

My exercise requires that I can use case-insensitive input. My approch is that I use the tolower and toupper function.

How can I convert the array to lowercase letters?

void KULstrcichr(char *arr, char search)
{
    printf("Return value when uppercase character %c is passed to isupper(): %d\n", search, isupper(search));
    // The  strchr() function returns a pointer to the first occurrence of the character c in the string s.
    if (isupper(search))
    {
        printf("Groß\n");
        char lowercasesearch = tolower(search);
        printf("Das ist der Output: %s", arr);
        char *ptr = strchr(arr, lowercasesearch);
        printf("Das ist der Buchstabe: %s", ptr);
    }
    else
    {
        printf("Klein\n");
        char upercasesearch = toupper(search);
        printf("Das ist der Output: %s", arr);
        char *ptr = strchr(arr, upercasesearch);
        printf("Das ist der Buchstabe: %s", ptr);
    }
}

CodePudding user response:

According to the title of the question

Make own strchr() function but case-insensitive

your code does not make any sense. You should write your own function similar to strchr that is declared in the C Standard like

char * strchr(const char *s, int c);

The function should be declared and defined the following way

char * my_strchr( const char *s, int c )
{
    c = tolower( ( unsigned char )c );

    while ( *s && tolower( ( unsigned char ) *s ) != c )   s;

    return c == '\0' || *s != '\0' ? ( char * )s : NULL;
}

CodePudding user response:

"How can I convert the array to lowercase letters?" - you don't. Instead, check character by character until you've reached the end of the string.

  • First convert the char you search for to lower (or upper) case.
    char lowsearch = tolower((unsigned char)search);
    
  • Then loop arr until *arr == '\0' and check each character on the way:
    for(;*arr != '\0';   arr) {
        if(tolower((unsigned char)*arr) == lowsearch) return arr;
    }
    return NULL;
    

Note that this requires that you return a char* just like strchr, not void

CodePudding user response:

This little assignment is more tricky than it looks:

  • your code does not always work because you only search either for uppercase or for lowercase, depending on the case of search, which does not cover all cases (pun intended).

  • using strchr first with uppercase, then with lowercase if uppercase was not found is still incorrect: you must find the first match for either case.

  • you must also find the null terminator if search is 0. Simple implementations usually fail this test.

  • tolower and toupper are not defined for negative values different from EOF, hence they should not be passed char values that can be negative on platforms where char is signed by default. Casting the char argument as (unsigned char) is a simple way to avoid this issue.

Here is an example:

// using int c for compatibility with char *strchr(const char *s, int c)
char *KULstrcichr(const char *s, int c) {
    int uc = tolower((unsigned char)c);

    for (;; s  ) {
        if (tolower(*(unsigned char *)s) == uc)
            return (char *)s;
        if (*s == '\0')
            return NULL;
    }
}

CodePudding user response:

How can I convert the array to lowercase letters? void KULstrcichr(char *arr, char search)

  • To achieve "Make own strchr() function but case-insensitive", use an interface like char *strchr(const char *s, int c); for maximum compatibility with that standard function.

  • Convert the search and *arr to a common case. e.g. tolower(). tolower(int ch) is defined for a ch in the unsigned char range and EOF.

Example:

char *TLG_strchr(const char *s, int c) {
  c = tolower((unsigned char)c);

  // str...() functions perform as if `s` was `unsigned char *`.
  const unsigned char *us = (const unsigned char *) s;

  while (tolower(*us) != c && *us) {
    us  ;
  }

  return tolower(*us) == c ? (char *) us : NULL;
}

Pedantic: (unsigned char)*s is incorrect for rare non-2's compliment machines with signed char. Better as *((unsigned char *)s), which is effectively what this answer does, to properly access negative char and distinguish 0 from -0. This likely will be a non-issue for the next version of C as that is expected to require 2's compliment.

CodePudding user response:

Since it looks like you're using simple 8-bit ASCII characters, note that a given uppercase character is just (lowercase & 0x20). Take the input character and run it through strchr() twice: once with a lowercase version, and once with an uppercase version.

char *myStrchr(const char *s, char c) {
    char *pLower;
    char *pUpper;
    char *p;

    c |= 0x20;
    pLower = strchr(s, c);
    c &= ~0x20;
    pUpper = strchr(s, c);
    if (pLower == NULL) {
        p = pUpper;
    } else if (pUpper == NULL) {
        p = pLower;
    } else {
        p = (pLower < pUpper) ? pLower : pUpper;
    }
    return p;
}

Note: I don't think you want your function to be of type void.

EDIT: if your input string may contain characters other than letters, you'll need to bound-check before performing the searches.

  • Related