String Versions of ctype Functions

The ctype functions are marvelous for single character manipulation and testing. Often, however, the functions appear in a loop so that they can be applied to an entire string. So why not write a string-based ctype function? Of course, that’s what I did.

Each function works with a sample string, one that contains uppercase and lowercase letters, as well as a smattering of symbols:

char sample[] = "This is Sample String #1 TEXT\n";

My goal was to apply three separate functions to this string:

  • str_tolower() to convert characters in the string to lowercase.
  • str_toupper() to convert characters in the string to uppercase.
  • str_toinverse() to switch lowercase characters to uppercase and vice-versa.

In all instances, I sought not to use any ctype functions, but manipulate the characters directly. Here is my code for the str_tolower() function:

2020_10_17-Lesson-a.c

#include <stdio.h>

void str_tolower(char *s)
{
    while(*s)
    {
        if( *s>='A' && *s<='Z' )
            *s |= 32;
        s++;
    }
}

int main()
{
    char sample[] = "This is Sample String #1 TEXT\n";

    printf("Before:\n%s",sample);
    str_tolower(sample);
    printf("After:\n%s",sample);

    return(0);
}

At Line 7, an if test determines whether the character is in the uppercase range. If so, a bitwise OR is performed to set the bit that converts the character to uppercase: *s |= 32;. (32 decimal is 0x20 hex.) Click here to review the Lesson from 2014 where I discuss this trick. Figure 1 shows a nifty graphic that explains how it works in detail.

Figure 1. Using bit manipulation to convert ‘A’ into ‘a’.

Here is sample output:

Before:
This is Sample String #1 TEXT
After:
this is sample string #1 text

The second function, str_toupper(), works similarly, though the if test at Line 7 checks for lowercase letters and the bitwise operation at Line 8 masks a bit to make the letter uppercase:

2020_10_17-Lesson-b.c

#include <stdio.h>

void str_toupper(char *s)
{
    while(*s)
    {
        if( *s>='a' && *s<='z' )
            *s &= 223;
        s++;
    }
}

int main()
{
    char sample[] = "This is Sample String #1 TEXT\n";

    printf("Before:\n%s",sample);
    str_toupper(sample);
    printf("After:\n%s",sample);

    return(0);
}

Figure 2 is an illustration from my ancient blog post, showing how the bitwise AND operator makes a lowercase character uppercase:

Figure 2. Using the logical & operator to convert from ‘a’ to ‘A’.

Here is the code’s output:

Before:
This is Sample String #1 TEXT
After:
THIS IS SAMPLE STRING #1 TEXT

The final function, str_inverse(), has no ctype counterpart in the standard C library. In the function, I test for uppercase letters and convert them to lowercase and vice-versa. The code includes statements from the two other functions:

2020_10_17-Lesson-c.c

#include <stdio.h>

void str_toinverse(char *s)
{
    while(*s)
    {
        if( *s>='A' && *s<='Z' )
        {
            *s |= 32;
            s++;
        }
        else if( *s>='a' && *s<='z' )
        {
            *s &= 223;
            s++;
        }
        else
            s++;
    }
}

int main()
{
    char sample[] = "This is Sample String #1 TEXT\n";

    printf("Before:\n%s",sample);
    str_toinverse(sample);
    printf("After:\n%s",sample);

    return(0);
}

If the character is uppercase (Line 7), the bitwise OR operator makes it lowercase at Line 9. If the character is lowercase (Line 12), the bitwise AND operator makes it uppercase at line 14. Each part of the if-else if-else structure contains the statement s++;. This ensures that the entire string is processed regardless of which character is encountered. Here’s the output:

Before:
This is Sample String #1 TEXT
After:
tHIS IS sAMPLE sTRING #1 text

In each example, a pointer is passed. This choice allows the string to be manipulated directly; nothing needs be returned. The address in variable s can be manipulated in the functions because doing so doesn’t alter the address outside the function. This flexibility is yet another way pointers can be useful.

Leave a Reply