C구조체와 문자열

ctype.h 문자 분류와 변환

`isdigit`·`isalpha`·`isspace` 등 문자 분류 함수와 `toupper`·`tolower` 변환 함수의 반환값 의미, `unsigned char` 캐스트가 필요한 이유, 입력 검증 패턴을 정리합니다.

마지막 수정 2026년 3월 26일

기본 패턴

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

char c = '5';
if (isdigit((unsigned char)c))    printf("숫자\n");
if (isalpha((unsigned char)c))    printf("알파벳\n");
if (isspace((unsigned char)c))    printf("공백\n");

char upper = toupper((unsigned char)'a');  // 'A'
char lower = tolower((unsigned char)'Z');  // 'z'

설명

분류 함수 — 참/거짓 반환

ctype.h 함수는 조건을 만족하면 0이 아닌 값, 불만족하면 0을 반환합니다. true/false가 아니라 비 0/0이므로 == 1 비교는 하지 않습니다.

c
// 주요 분류 함수
isdigit(c)   // '0'~'9'
isalpha(c)   // 'a'~'z', 'A'~'Z'
isalnum(c)   // isdigit || isalpha
isspace(c)   // ' ', '\t', '\n', '\r', '\f', '\v'
isupper(c)   // 'A'~'Z'
islower(c)   // 'a'~'z'
ispunct(c)   // 구두점 (!, @, # 등)
isprint(c)   // 출력 가능 문자 (space 포함)
iscntrl(c)   // 제어 문자 (\0, \n, \t 등)
isxdigit(c)  // 16진수 숫자 ('0'~'9', 'a'~'f', 'A'~'F')

입력 검증 패턴

문자열이 조건을 만족하는지 검사하는 전형적인 패턴입니다.

c
#include <string.h>

// 문자열 전체가 숫자인지 확인
int is_all_digits(const char *s) {
    if (*s == '\0') return 0;   // 빈 문자열 거부
    for (; *s != '\0'; s++) {
        if (!isdigit((unsigned char)*s)) return 0;
    }
    return 1;
}

// 첫 글자 알파벳, 나머지 알파벳+숫자인지 (식별자 검증)
int is_identifier(const char *s) {
    if (!isalpha((unsigned char)*s) && *s != '_') return 0;
    for (s++; *s != '\0'; s++) {
        if (!isalnum((unsigned char)*s) && *s != '_') return 0;
    }
    return 1;
}

변환 함수 — toupper / tolower

toupper/tolower는 해당 변환이 가능한 문자만 바꾸고, 불가능한 문자(숫자, 구두점 등)는 그대로 반환합니다.

c
// 문자열 전체 소문자화
void to_lower_str(char *s) {
    for (; *s != '\0'; s++) {
        *s = (char)tolower((unsigned char)*s);
    }
}

// 대소문자 무시 비교
int strcasecmp_manual(const char *a, const char *b) {
    while (*a && *b) {
        int diff = tolower((unsigned char)*a) - tolower((unsigned char)*b);
        if (diff != 0) return diff;
        a++; b++;
    }
    return tolower((unsigned char)*a) - tolower((unsigned char)*b);
}

unsigned char 캐스트가 필요한 이유

ctype.h 함수의 인자는 int이고, unsigned char 범위 또는 EOF(-1) 여야 합니다. char가 부호 있는(signed) 플랫폼에서 음수 문자를 그대로 전달하면 정의되지 않은 동작입니다.

c
// ❌ signed char가 음수이면 UB (예: 한글 등 0x80 이상 바이트)
char c = (char)0xE0;
isalpha(c);   // c = -32 — 범위 밖, UB

// ✅ 항상 unsigned char로 캐스트
isalpha((unsigned char)c);   // 안전

빠른 정리

목적함수
숫자 문자 확인isdigit(c)
알파벳 확인isalpha(c)
알파벳 또는 숫자isalnum(c)
공백 계열 확인isspace(c)
대문자 확인 / 변환isupper(c) / toupper(c)
소문자 확인 / 변환islower(c) / tolower(c)
16진수 문자 확인isxdigit(c)

주의할 점

ctype.h 함수에 char를 직접 전달하면 signed char 플랫폼에서 정의되지 않은 동작입니다. 항상 (unsigned char) 캐스트를 씁니다.

c
// ❌ 루프에서 캐스트 없이 사용 — 잠재적 UB
char *s = some_string;
while (*s && isalpha(*s)) s++;   // *s가 음수이면 UB

// ✅ 캐스트 추가
while (*s && isalpha((unsigned char)*s)) s++;

// ❌ 반환값을 bool처럼 == 1 비교
if (isdigit((unsigned char)c) == 1) { ... }  // 반환값이 1이 아닐 수 있음

// ✅ 0이 아닌지만 확인
if (isdigit((unsigned char)c)) { ... }

참고 링크

1 sources