Table of Contents

ctype.h

ctype.h gives you the character classification and conversion functions you reach for when parsing input character by character. If you have ever written if (c >= 'a' && c <= 'z') to check for a lowercase letter, these functions are the right way to do it — they handle the full range of unsigned char values correctly and respect the current locale.

#include <ctype.h>
 
isalpha('a')   // non-zero: it's a letter
isdigit('7')   // non-zero: decimal digit
isalnum('Z')   // non-zero: letter or digit
isspace(' ')   // non-zero: space, tab, newline, \r, \f, \v
isupper('A')   // non-zero: uppercase letter
islower('b')   // non-zero: lowercase letter
ispunct('!')   // non-zero: printable, not space, not alnum
isprint('~')   // non-zero: printable including space
iscntrl('\n')  // non-zero: control character
 
toupper('a')   // 'A'
tolower('Z')   // 'z'

There is one gotcha: these functions take an int that must be either an unsigned char value or EOF. If you pass a plain char and your platform has signed char (most do), characters above 127 come in as negative values and trigger undefined behaviour. Always cast: isalpha((unsigned char)c).

The functions are locale-dependent. isalpha returns non-zero for letters in the current locale, which may include é, ü, ñ and other characters outside ASCII.

Practice

// compile: gcc -o ident ident.c
// run: echo "hello_world" | ./ident      echo "123bad" | ./ident
// description: validate whether stdin contains a valid C identifier
 
#include <ctype.h>
#include <stdio.h>
 
int main(void) {
    int c, pos = 0, valid = 1;
    while ((c = getchar()) != '\n' && c != EOF) {
        unsigned char uc = (unsigned char)c;
        if (pos == 0 && !isalpha(uc) && c != '_') valid = 0;
        if (pos > 0 && !isalnum(uc) && c != '_')  valid = 0;
        pos++;
    }
    puts(valid && pos > 0 ? "valid identifier" : "not valid");
    return 0;
}

Try hello_world (valid), 123bad (fails: starts with a digit), _ok (valid), and café — the last one will vary by locale, which is a useful reminder that isalpha sees locale-defined letters, not just ASCII. The (unsigned char) cast is the correct form in production code.