What's an alternate way of getting the char's int value to increment?

115 views Asked by At

While in the progress of making string functions, I have tried building a function somewhere similar to strlwr() which I named lowercase():

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

char *lowercase(char *text);

int main() {
    char *hello = "Hello, world!";
    printf("%s\n", lowercase(hello));
}

char *lowercase(char *text) {
    for (int i = 0; ; i++) {
        if (isalpha(text[i])) {
            (int) text[i] += ('a' - 'A');
            continue;
        } else if (text[i] == '\0') {
            break;
        }
    }
    return text;
}

I learned that the gap for a big letter and small letter would be 32, which is what I used. But then I got this error:

lowercase.c:14:13: error: assignment to cast is illegal, lvalue casts are not supported
            (int) text[i] += 32;
            ^~~~~~~~~~~~~ ~~

I want to increment the value of the char if it is considered a letter from A-Z. Turns out I can't, since the char is in an array, and the way I'm doing it doesn't seem to make sense for the computer.

Q: What alternate ways can I use to complete this function? Can you explain further why this error is like this?

2

There are 2 answers

7
Vlad from Moscow On BEST ANSWER

Though in C string literals have types of non-constant character arrays nevertheless you may not change string literals.

char *hello = "Hello, world!";

From the C Standard (6.4.5 String literals)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

So you should declare the identifier hello like a character array

char hello[] = "Hello, world!";

Within the function you should not use magic numbers like 32. For example if the compiler uses the EBCDIC coding your function will produce a wrong result.

And in the loop instead of the type int you have to use the type size_t because an object of the type int can be unable to store all values of the type size_t that is the return type of the sizeof operator or of the function strlen.

This statement

(int) text[i] += 32;

does not make a sense because in the left side of the expression there is an rvalue due to the casting.

The function can be implemented the following way

char * lowercase( char *text ) 
{
    for ( char *p = text; *p; ++p ) 
    {
        if ( isalpha( ( unsigned char )*p ) ) 
        {
            *p = tolower( ( unsigned char )*p );
        } 
    }

    return text;
}
2
John Kugelman On

The cast is unnecessary. chars are integral types and can be incremented without fanfare:

text[i] += 32;

As several commenters have noted, you should also change your string to a modifiable string. char *hello = "..." declares a read-only string literal. Use array syntax to make it writable.

char hello[] = "Hello, world!";

You'll also want to switch isalpha() to isupper() so you only modify uppercase letters.

By the way, if you move the else if check into the for loop's test condition you can get rid of both the break and the continue.

for (int i = 0; text[i] != '\0'; i++) {
    if (isupper((unsigned char) text[i])) {
        text[i] += 32;
    }
}