简体   繁体   中英

Make own strchr() function but case-insensitive

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);
    }
}

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;
}

Here is a demonstration program.

#include <stdio.h>
#include <ctype.h>

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;
}

int main( void )
{
    char s[] = "Hello";
    char *p = my_strchr( s, 'h' );

    if (p != NULL)
    {
        printf( "position = %td, substring = %s\n", p - s, s );
    }
}

The program output is

position = 0, substring = Hello

"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

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. eg 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.

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;
    }
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM