Trying to convert uppercase char to lowercase in C

2019-03-01 00:24发布

问题:

I am trying to convert a char element from an char *argv[] array to lowercase from uppercase without using a function. I want to add 32 to the ascii integer.

When I try to pass the variable as an argument, it will show the integer sum, but not the new lowercase character. Instead it shows the following output:

letter h, 104
tolower: 136, �

Code:

int i = 0;
for(i = 0; argv[1][i] != '\0'; i++) {
    char letter = argv[1][i];

    printf("letter %c, %i\n", letter, letter);
    char tolower = argv[1][i];
    int lowercase = tolower + 32;

    printf("tolower: %i, %c\n", lowercase, lowercase);
}

Why is it printing a "?" char?

回答1:

First, don't assume you are using an ascii character set (ie, 32 is the wrong additive value in some character sets). The problem you are having is that 'h' + 32 is not a lower case "h". 'h' is already lowercase, so you want to be adding 0. Check it; something like:

if( tolower >= 'A' && tolower <= 'Z' )
  tolower += 'a' - 'A';


回答2:

I will not point the problems that other answerers did, I will show a neat trick to perform the swap upper-lower. For the letters, the difference between the lower case and the upper case letters is the bit 5 in the ascii code. So to set the letter lowercase you need to set this bit:

lower = 0x20 | letter;

For uppercase reset the bit:

upper = (~0x20) & letter;

And to swap the case you can use XOR:

swapped = 0x20 ^ letter;

The good thing here that you don't have to worry and check whether or not the letter is already the case you need.

Of course the assumption here is that your system is using ASCII encoding.



回答3:

Ascii 136 is not a printable character. You should do something like lowercase = tolower - 'A' + 'a';, but only if tolower is uppercase for sure (it's not in your example).



回答4:

This is from my own C++ library, but it works for C too as well.

Self-Optimized (Library Function)

// return the specified letter in lowercase
char tolower(int c)
{
    // (int)a = 97, (int)A = 65
    // (a)97 - (A)65 = 32
    // therefore 32 + 65 = a
    return c > 64 && c < 91 ? c + 32 : c;
}
// return the specfied letter in uppercase
char toupper(int c)
{
    // (int)a = 97, (int)A = 65
    // (a)97 - (A)65 = 32
    // therefore 97 - 32 = A
    return c > 96 && c < 123 ? c - 32 : c;
}

The return value is a printable char. However, some modern compilers may have optimized the code as this already if you're going to do the way below.

Readable

char tolower(int c)
{
    return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
}
char toupper(int c)
{
    return c >= 'a' && c <= 'z' ? c - ('a' - 'A') : c;
}

Note that the difference between a and A is a 32 constant.