toupper and tolower implementation for whole c-strings

tux4life 0 Tallied Votes 3K Views Share

This is a toupper and tolower implementation for whole c-strings, without making use of the existing toupper and tolower functions for characters :)

example:

char s[]="Hello, beautiful world!";
stoupper(s); // s now contains: `HELLO, BEAUTIFUL WORLD!´
stolower(s); // s now contains: `hello, beautiful world!´
/**
@author: Mathias Van Malderen (tux4life)
*/

void stoupper(char *s)
{
    for(; *s; s++)
        if(('a' <= *s) && (*s <= 'z'))
            *s = 'A' + (*s - 'a');
}

void stolower(char *s)
{
    for(; *s; s++)
        if(('A' <= *s) && (*s <= 'Z'))
            *s = 'a' + (*s - 'A');
}

Dani AI

Generated

Nice thread. @William Hemsworth’s bit-hack is clever, and ’s concern about non-ASCII data is the gotcha most people hit. If you truly want a dependency-free, per-byte transform that mirrors what your example shows (and only for letters a..z / A..Z), a simple, explicit range check is portable and easy to read. It also avoids UB from sign-extended chars and does not call toupper/tolower.

#include <stddef.h>

void stoupper_ascii(char *s) {
    if (!s) return;
    for (unsigned unsigned char *p = (unsigned unsigned char *)s; *p; ++p) {
        if (*p >= 'a' && *p <= 'z') *p -= ('a' - 'A');
    }
}

void stolower_ascii(char *s) {
    if (!s) return;
    for (unsigned unsigned char *p = (unsigned unsigned char *)s; *p; ++p) {
        if (*p >= 'A' && *p <= 'Z') *p += ('a' - 'A');
    }
}

Practical tips, based on points raised above:

  • If you later switch to the ctype macros (as in ’s approach), always cast the input byte to unsigned char before calling isupper, islower, toupper, or tolower. Passing a negative char value is undefined.
  • Avoid for (i = 0; i < strlen(s); ++i); either cache the length or, simpler, iterate until '\0' as above to prevent O(n^2) behavior on some libc implementations.
  • Working with UTF-8 or other multibyte encodings? Do not transform per byte. Convert to wide characters and use towupper/towlower, then convert back. A common pattern is: set the locale (setlocale(LC_CTYPE, "")), stream the input with mbrtowc, map with towupper, and emit with wcrtomb into a separate buffer sized to strlen(s) * MB_CUR_MAX + 1. This handles accented letters correctly and avoids the mojibake @William Hemsworth mentioned.
  • On Windows APIs mentioned by , note they operate with wide strings and locale/LCMap flags; they are fine when you specifically target Windows and want locale-aware casing rules.
William Hemsworth 1,339 Posting Virtuoso

Shorter, but perhaps not any more efficient.

void stoupper(char *s) {
  do if (96 == (224 & *s)) *s &= 223;
  while (*s++);
}

Wow, I'm competitive. No doubt there's some mistake in mine though.

Here's how it works:

the first lowercase letter 'a' has a binary of: 01100001
the last lowercase letter 'z' has a binary of: 01111010

Both these letters have 01100000 in common.
But if the bit 10000000 is on, then it cant be a letter.

So by doing an AND check with 11100000 and comparing (==) it with the value 01100000, it should determine whether or not the character is a valid lowercase letter.

Then remove the bit 00100000 to make the character a capital.

Am I good or what? :D

nalply 0 Newbie Poster

Works only for ASCII. Your résumé will be uppercased to RéSUMé or bungle the e with accent. Nice, isn't it?

William Hemsworth 1,339 Posting Virtuoso

Obviously only works with ascii and doesn't support unicode, otherwise char* would have been used. Either way, using the toupper function there outputs: RÚSUMÚ for me (even though it's most probably just a font problem). I would rather it printed RéSUMé :] Both these codes simply turn any characters between 'a' to 'z' and makes them uppercase.

tux4life 2,072 Postaholic

Hi, naply, take a look at and you'll see that toupper only converts alphabet letters to uppercase (this is analog for tolower), I intended my code to do 'exactly' the same :)

WH>Am I good or what?
Yes, you're the best :P

MosaicFuneral 812 Nearly a Posting Virtuoso

Or just use XOR 32 to swap the values of a valid range. Ta-da...

AuSsIeStOnE 0 Newbie Poster

unsigned char string[];

///////// Convert entire string: uppercase to lowercase ////////

for (i=0; i<strlen(string); i++)
if (isupper(string))
string=tolower(string);

///////// Convert entire string: lowercase to uppercase ////////

for (i=0; i<strlen(string); i++)
if (islower(string))
string=toupper(string);

mika_ -3 Newbie Poster

On Windows, use Shell apis (1 line of code...)

William Hemsworth 1,339 Posting Virtuoso

This is the implementation, firstly you can't do this in one line, and even if you could nobody would care.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.