How can I convert a mixed case string to a lowercase string in C?
            Asked
            
        
        
            Active
            
        
            Viewed 3.5e+01k times
        
    140
            
            
        - 
                    2Are you just dealing with ASCII with letters a-z only? – Mark Byers Apr 18 '10 at 09:52
- 
                    1ascii. 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? – Tony Stark Apr 18 '10 at 10:10
- 
                    1That will work. I was more thinking if your string contains things like é or Ü. – Mark Byers Apr 18 '10 at 10:46
- 
                    4Why not just use "strlwr"? `strlwr((char*)str);` It just goes through the string and converts it itself. – Larry Mar 01 '18 at 23:49
- 
                    1@Larry It's non-standard. – mid May 28 '18 at 20:45
6 Answers
206
            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);
 
    
    
        Evan Carroll
        
- 78,363
- 46
- 261
- 468
 
    
    
        Earlz
        
- 62,085
- 98
- 303
- 499
- 
                    41
- 
                    15@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) – Earlz Apr 18 '10 at 10:05
- 
                    1this gives me a segfault if str is a `char *`, but not if str is a char array. Got any explanation for that? – Electric Coffee Nov 22 '16 at 22:07
- 
                    @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"`. – Jan Sep 05 '17 at 11:42
- 
                    4I believe the one liner will cause you to lose your pointer to the string. – Ace.C Sep 08 '17 at 19:55
- 
                    2
- 
                    
- 
                    1@jfs Why not `while (*p = tolower(*p)) ++p;` or `while (*p = tolower(*p++))` for the purpose of obfuscation (the latter only works since C++17) ;-) – L. F. May 18 '19 at 07:46
- 
                    1The 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](https://stackoverflow.com/users/5352244/nop-da-call). – thetva Nov 01 '22 at 18:28
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;
 
    
    
        Deduplicator
        
- 44,692
- 7
- 66
- 118
 
    
    
        Oleg Razgulyaev
        
- 5,757
- 4
- 28
- 28
- 
                    7To make it slightly more readable you could do `for(char *p = pstr;*p;++p) *p=*p>='A'&&*p<='Z'?*p|0x60:*p;` – Grant Peters Apr 18 '10 at 10:54
- 
                    8This version is actually slower than glibc's `tolower()`. 55.2 vs. 44.15 on my machine. – jfs Apr 18 '10 at 18:10
- 
                    i can't imagine that: tolower() deals with chars; only if it's macro – Oleg Razgulyaev Apr 18 '10 at 18:37
- 
                    1@oraz: tolower() has `int (*)(int)` signature. Here's the code used for performance measurements http://gist.github.com/370497 – jfs Apr 18 '10 at 19:32
- 
                    @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;} – Oleg Razgulyaev Apr 18 '10 at 20:27
- 
                    @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. – jfs Apr 18 '10 at 21:33
- 
                    1
- 
                    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. – Andrew Henle Jul 02 '20 at 23:25
6
            
            
        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;
}
 
    
    
        cscan
        
- 364
- 2
- 9
- 
                    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`.` – NewbiZ Mar 08 '22 at 02:32
- 
                    @NewbiZ, indeed: // convert string to lowercase, in place: char* toLower(char* p) { for( ; *p; p++) *p=tolower(*p); return p; } – Felipe G. Nievinski Jun 26 '23 at 04:18
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.
- 
                    6Yeah, 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. – Ken S May 22 '13 at 21:26
- 
                    1This post is discussed on [meta](http://meta.stackoverflow.com/questions/270402/is-ghetto-an-offensive-word). – Patrick Hofman Sep 02 '14 at 08:31
- 
                    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? – 9a3eedi Mar 21 '22 at 11:20
-1
            
            
        Are you just dealing with ASCII strings, and have no locale issues? Then yes, that would be a good way to do it.
 
    
    
        Mark Byers
        
- 811,555
- 193
- 1,581
- 1,452
- 
                    what happens if tolower() is called on a non-ascii a-z char? like '!' or '#'. i tested it on '#' and it seemed to work ok. is this generally true for all ascii chars that aren't letters a-z? – Tony Stark Apr 18 '10 at 10:29
- 
                    1@hatorade: `tolower()` leaves argument unchanged if it is not in 'A'..'Z' range. – jfs Apr 18 '10 at 18:20
- 
                    2! and # are both ascii chars. Mark was referring to other encodings like UTF8, where you can't assume that there is one byte per character (as this solution does) – hdgarrood Nov 23 '12 at 12:31
- 
                    
 
     
     
     
    