How do I lowercase a string in C?
Asked Answered
I

6

144

How can I convert a mixed case string to a lowercase string in C?

Ideational answered 18/4, 2010 at 9:36 Comment(5)
Are you just dealing with ASCII with letters a-z only?Anastigmatic
ascii. how would i take that into account? would the example below still work? what happens if my char is a '#' and tolower() gets called on it?Ideational
That will work. I was more thinking if your string contains things like é or Ü.Anastigmatic
Why not just use "strlwr"? strlwr((char*)str); It just goes through the string and converts it itself.Isocline
@Isocline It's non-standard.Tortoise
S
210

It's in the standard library, and that's the most straight forward way I can see to implement such a function. So yes, just loop through the string and convert each character to lowercase.

Something trivial like this:

#include <ctype.h>

for(int i = 0; str[i]; i++){
  str[i] = tolower(str[i]);
}

or if you prefer one liners, then you can use this one by J.F. Sebastian:

for ( ; *p; ++p) *p = tolower(*p);
Sheba answered 18/4, 2010 at 9:44 Comment(10)
for ( ; *p; ++p) *p = tolower(*p); seems more idiomatic.Convulsion
@J.F. there you go. Depends on if they want the code to look scary or nice :) (very readable one liner, but it does look scary)Sheba
this gives me a segfault if str is a char *, but not if str is a char array. Got any explanation for that?Profanity
@ElectricCoffee I guess if you used char * you used really a string constant which gets placed in unwriteable memory section. So if you try to change the value of that it gives you a segfault. If, on the other hand, you would copy that constant string to a char *copy = strdup (const_string) then copy could be altered because it is allocated on the heap, which is writeable. So all in all it does not have anything to do with using a pointer (char *) but with using constant strings like in code: char *const_str = "my const string".Tureen
I believe the one liner will cause you to lose your pointer to the string.Uterus
I believe that one liner will have untold ramifications.Labbe
the one-liner results in error: lvalue required as increment operandDahle
@Convulsion Why not while (*p = tolower(*p)) ++p; or while (*p = tolower(*p++)) for the purpose of obfuscation (the latter only works since C++17) ;-)Jacks
The last character in the c string represented by p is the character '\0' numericaly represented as literal 0. So when it encounters the last character as it increments, the loop terminates since it is falsy. I believe there are no ramifications NOP da CALL.Heathenish
You forgot to convert the (possibly signed) char value before passing to tolower() (which requires positive versions of characters, or EOF).Rudolph
R
9

to convert to lower case is equivalent to rise bit 0x60 if you restrict yourself to ASCII:

for(char *p = pstr; *p; ++p)
    *p = *p > 0x40 && *p < 0x5b ? *p | 0x60 : *p;
Rheumy answered 18/4, 2010 at 10:36 Comment(8)
To make it slightly more readable you could do for(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p;Animosity
This version is actually slower than glibc's tolower(). 55.2 vs. 44.15 on my machine.Convulsion
i can't imagine that: tolower() deals with chars; only if it's macroRheumy
@oraz: tolower() has int (*)(int) signature. Here's the code used for performance measurements gist.github.com/370497Convulsion
@J.F.: i see, they've used table, but i can optimize: for ( ; *p; ++p) if(*p > 'Z') {continue;} else if (*p < 'A') {continue;} else {*p = *p|0x60;}Rheumy
@oraz: if (*p > 'Z') optimization performs better on the input I've used, but if there are many upper-case letters it takes the same time as the previous version.Convulsion
The fastest version uses a lookup table instead of branches.Chandachandal
Note that this is an ASCII-only conversion that is not strictly conforming C. C provides no guarantees that upper- (or lower-)case letter are represented consecutively in any character set.Wily
V
7

Looping the pointer to gain better performance:

#include <ctype.h>

char* toLower(char* s) {
  for(char *p=s; *p; p++) *p=tolower(*p);
  return s;
}
char* toUpper(char* s) {
  for(char *p=s; *p; p++) *p=toupper(*p);
  return s;
}
Vivica answered 30/4, 2020 at 8:1 Comment(4)
Well if you're going the one-liner way, then s is a local variable in your function, you can directly use it instead of declaring p.`Spiritualize
@NewbiZ, indeed: // convert string to lowercase, in place: char* toLower(char* p) { for( ; *p; p++) *p=tolower(*p); return p; }Characterize
@NewbiZ, not given this signature (which returns pointer to the start of string). A copy needs to be made somewhere!Rudolph
@TobySpeight, oh right indeedSpiritualize
Z
1

If we're going to be as sloppy as to use tolower(), do this:

char blah[] = "blah blah Blah BLAH blAH\0";
int i = 0;
while( blah[i] |=' ', blah[++i] ) {}

But, well, it kinda explodes if you feed it some symbols/numerals, and in general it's evil. Good interview question, though.

Zygodactyl answered 22/5, 2013 at 5:14 Comment(3)
Yeah, this will fold/spindle/mutilate a variety of symbols (in ASCII, any symbol, control character, or numeral with bit 5 clear will become the same character code with bit 5 set, etc) so really, seriously, don't use it.Zygodactyl
This post is discussed on meta.Imperative
Can you elaborate more? When I read about tolower(), they all mention that they only work on characters that have a lowercase character defined for them. From opengroup.org: "If the argument of tolower() represents an uppercase letter, and there exists a corresponding lowercase letter [CX] [Option Start] (as defined by character type information in the program locale category LC_CTYPE ), [Option End] the result shall be the corresponding lowercase letter. All other arguments in the domain are returned unchanged." If this is the case, where does tolower() fail?Gidgetgie
S
-1

You may use this user defined function:

char *ToLower(char *text){

    int stringlength=strlen(text);
    char *lower=(char*)malloc(sizeof(char)*stringlength);
    int i=0;

    while(i<stringlength){
        //checking if the character is an uppercase
        if((text[i]-'A')<=25){

            lower[i]=text[i]+32;
        }
        //if the character is lowercase
        else{

            lower[i]=text[i];
        }

        i++;
    }

    return lower;
}
Swats answered 4/4 at 16:49 Comment(1)
depending on the encoding, (text[i]-'A')<=25 can be true for values different than [A-Z]Subaquatic
T
-2

I'm new to C and have been trying hard to convert strings from uppercase to lowercase. I made the mistake of changing the string 'A' + 32 = 'a'. And I can't solve the problem.

I used char type and finally I was able to convert it to string type. You can consult:

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

string convert_lower(string str)
{
    int length = strlen(str);
    char c[length + 1];

    for (int i = 0; i < length; i++)
    {
        if (str[i] <= 'Z' || str[i] >= 'A')
        {
            c[i] = tolower((char)str[i]);
        }
    }
    c[length] = '\0';
    string text = c;
    return text;
}
Twila answered 11/10, 2023 at 13:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.