閉じる

【C言語】toupperとtolowerで大文字・小文字を変換する方法

英字の大文字や小文字を手作業で判定して変換する必要はありません。

touppertolowerを使えば、文字や文字列を簡単に変換できます。

本記事では1文字の基本から文字列全体の変換方法、初心者がつまずきやすい注意点までを丁寧に解説します。

特にunsigned charへのキャストと文字列リテラルの扱いは必ず押さえましょう

toupperとtolowerの基本

大文字・小文字を変換する関数

toupperは小文字を大文字に、tolowerは大文字を小文字に変換する標準関数です

変換対象が英字でない場合や、すでに目的の大文字/小文字である場合はそのままの文字が返ります。

以下が関数のプロトタイプです。

C言語
int toupper(int c);
int tolower(int c);

返り値はint型ですが、実質的には1バイトの文字が入っています。

引数はEOFまたはunsigned charに変換可能な値でなければなりません。

負のcharをそのまま渡すのは未定義動作のため、常に(unsigned char)にキャストしてから渡すのが安全です

次の表に要点を整理します。

関数役割変換対象返り値
toupper小文字→大文字英字小文字のみ変換後の文字(非対象はそのまま)
tolower大文字→小文字英字大文字のみ変換後の文字(非対象はそのまま)

使う前にincludeする

これらの関数は<ctype.h>で宣言されています

入出力のために<stdio.h>もよく一緒に使います。

C言語
#include <ctype.h>  // toupper, tolower
#include <stdio.h>  // printf

ロケールの影響: これらの関数はロケールに依存しますが、標準的な「C」ロケールではASCII英字のみが対象です。

UTF-8の日本語は変換されません(後述します)。

1文字を変換する基本の使い方

1文字の変換は、渡して返ってきた値をcharにキャストし直すだけです

必ず(unsigned char)にキャストしてから渡します。

C言語
#include <ctype.h>
#include <stdio.h>

int main(void) {
    char a = 'a';
    // 安全のため(unsigned char)にキャストしてから渡す
    char up = (char)toupper((unsigned char)a);

    char z = 'Z';
    char low = (char)tolower((unsigned char)z);

    printf("a -> %c (ASCII %d)\n", up, (int)up);
    printf("Z -> %c (ASCII %d)\n", low, (int)low);

    return 0;
}
実行結果
a -> A (ASCII 65)
Z -> z (ASCII 122)

1文字の変換例

文字から大文字に変換する

小文字1文字を大文字に変換する最小例です

C言語
#include <ctype.h>
#include <stdio.h>

int main(void) {
    char c = 'b';
    char upper = (char)toupper((unsigned char)c);
    printf("before: %c, after: %c\n", c, upper);
    return 0;
}
実行結果
before: b, after: B

文字から小文字に変換する

大文字1文字を小文字に変換する例です

C言語
#include <ctype.h>
#include <stdio.h>

int main(void) {
    char c = 'Q';
    char lower = (char)tolower((unsigned char)c);
    printf("before: %c, after: %c\n", c, lower);
    return 0;
}
実行結果
before: Q, after: q

英字以外はそのまま

数字や記号、空白などは変換対象ではないため、そのまま返ります

C言語
#include <ctype.h>
#include <stdio.h>

int main(void) {
    char d = '9';
    char q = '?';
    char sp = ' ';

    char d_u = (char)toupper((unsigned char)d);
    char d_l = (char)tolower((unsigned char)d);

    char q_u = (char)toupper((unsigned char)q);
    char q_l = (char)tolower((unsigned char)q);

    char sp_u = (char)toupper((unsigned char)sp);
    char sp_l = (char)tolower((unsigned char)sp);

    printf("'9' -> toupper: %c, tolower: %c\n", d_u, d_l);
    printf("'?' -> toupper: %c, tolower: %c\n", q_u, q_l);
    printf("' ' -> toupper: %c, tolower: %c\n", sp_u, sp_l);
    return 0;
}
実行結果
'9' -> toupper: 9, tolower: 9
'?' -> toupper: ?, tolower: ?
' ' -> toupper:  , tolower:

文字列を大文字・小文字に変換する

for文で末尾(‘\0’)まで処理

文字列はcharの配列で、末尾にヌル文字'\0'がつきます。

先頭から'\0'に出会うまでループして各文字を変換します

判定は不要で、毎回toupper/tolowerを呼べば充分です。

C言語
#include <ctype.h>
#include <stdio.h>

// その場で大文字化する関数
void str_to_upper_inplace(char *s) {
    // s[i] が '
#include <ctype.h>
#include <stdio.h>
// その場で大文字化する関数
void str_to_upper_inplace(char *s) {
// s[i] が '\0' になるまでループ
for (size_t i = 0; s[i] != '\0'; ++i) {
// 未定義動作を避けるため(unsigned char)で受け渡し
s[i] = (char)toupper((unsigned char)s[i]);
}
}
// その場で小文字化する関数
void str_to_lower_inplace(char *s) {
for (size_t i = 0; s[i] != '\0'; ++i) {
s[i] = (char)tolower((unsigned char)s[i]);
}
}
int main(void) {
char s1[] = "AbcD! 123";
str_to_upper_inplace(s1);
printf("UPPER: %s\n", s1);
char s2[] = "AbcD! 123";
str_to_lower_inplace(s2);
printf("lower: %s\n", s2);
return 0;
}
' になるまでループ for (size_t i = 0; s[i] != '
#include <ctype.h>
#include <stdio.h>
// その場で大文字化する関数
void str_to_upper_inplace(char *s) {
// s[i] が '\0' になるまでループ
for (size_t i = 0; s[i] != '\0'; ++i) {
// 未定義動作を避けるため(unsigned char)で受け渡し
s[i] = (char)toupper((unsigned char)s[i]);
}
}
// その場で小文字化する関数
void str_to_lower_inplace(char *s) {
for (size_t i = 0; s[i] != '\0'; ++i) {
s[i] = (char)tolower((unsigned char)s[i]);
}
}
int main(void) {
char s1[] = "AbcD! 123";
str_to_upper_inplace(s1);
printf("UPPER: %s\n", s1);
char s2[] = "AbcD! 123";
str_to_lower_inplace(s2);
printf("lower: %s\n", s2);
return 0;
}
'; ++i) { // 未定義動作を避けるため(unsigned char)で受け渡し s[i] = (char)toupper((unsigned char)s[i]); } } // その場で小文字化する関数 void str_to_lower_inplace(char *s) { for (size_t i = 0; s[i] != '
#include <ctype.h>
#include <stdio.h>
// その場で大文字化する関数
void str_to_upper_inplace(char *s) {
// s[i] が '\0' になるまでループ
for (size_t i = 0; s[i] != '\0'; ++i) {
// 未定義動作を避けるため(unsigned char)で受け渡し
s[i] = (char)toupper((unsigned char)s[i]);
}
}
// その場で小文字化する関数
void str_to_lower_inplace(char *s) {
for (size_t i = 0; s[i] != '\0'; ++i) {
s[i] = (char)tolower((unsigned char)s[i]);
}
}
int main(void) {
char s1[] = "AbcD! 123";
str_to_upper_inplace(s1);
printf("UPPER: %s\n", s1);
char s2[] = "AbcD! 123";
str_to_lower_inplace(s2);
printf("lower: %s\n", s2);
return 0;
}
'; ++i) { s[i] = (char)tolower((unsigned char)s[i]); } } int main(void) { char s1[] = "AbcD! 123"; str_to_upper_inplace(s1); printf("UPPER: %s\n", s1); char s2[] = "AbcD! 123"; str_to_lower_inplace(s2); printf("lower: %s\n", s2); return 0; }
実行結果
UPPER: ABCD! 123
lower: abcd! 123

配列の文字列をその場で変換

書き換え可能なchar配列なら、同じ配列の中で直接変換できます

代表的な例を示します。

C言語
#include <ctype.h>
#include <stdio.h>

int main(void) {
    // 文字列リテラルから初期化したchar配列は書き換え可能
    char s[] = "Hello, C Language! 123";
    for (size_t i = 0; s[i] != '
#include <ctype.h>
#include <stdio.h>
int main(void) {
// 文字列リテラルから初期化したchar配列は書き換え可能
char s[] = "Hello, C Language! 123";
for (size_t i = 0; s[i] != '\0'; ++i) {
s[i] = (char)toupper((unsigned char)s[i]); // その場で大文字化
}
printf("%s\n", s);
return 0;
}
'; ++i) { s[i] = (char)toupper((unsigned char)s[i]); // その場で大文字化 } printf("%s\n", s); return 0; }
実行結果
HELLO, C LANGUAGE! 123

別バッファに書き込んで変換

元の文字列を残したい場合は、別のバッファに書き込む方法が安全です

バッファサイズを受け取って、あふれないように終端'\0'を付けます。

C言語
#include <ctype.h>
#include <stdio.h>
#include <string.h>

// srcを小文字化してdstへコピーする安全な関数
void str_to_lower_copy(const char *src, char *dst, size_t dst_size) {
    if (dst_size == 0) return; // バッファが無ければ何もしない
    size_t i = 0;
    for (; src[i] != '
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// srcを小文字化してdstへコピーする安全な関数
void str_to_lower_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return; // バッファが無ければ何もしない
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
// unsigned charにキャストしてからtolowerを呼ぶ
dst[i] = (char)tolower((unsigned char)src[i]);
}
dst[i] = '\0'; // 必ず終端を付ける
}
int main(void) {
const char *src = "AbC-XYZ 123";
char dst[64]; // 十分な大きさのバッファを用意
str_to_lower_copy(src, dst, sizeof(dst));
printf("src: %s\n", src);
printf("dst: %s\n", dst);
return 0;
}
' && i + 1 < dst_size; ++i) { // unsigned charにキャストしてからtolowerを呼ぶ dst[i] = (char)tolower((unsigned char)src[i]); } dst[i] = '
#include <ctype.h>
#include <stdio.h>
#include <string.h>
// srcを小文字化してdstへコピーする安全な関数
void str_to_lower_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return; // バッファが無ければ何もしない
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
// unsigned charにキャストしてからtolowerを呼ぶ
dst[i] = (char)tolower((unsigned char)src[i]);
}
dst[i] = '\0'; // 必ず終端を付ける
}
int main(void) {
const char *src = "AbC-XYZ 123";
char dst[64]; // 十分な大きさのバッファを用意
str_to_lower_copy(src, dst, sizeof(dst));
printf("src: %s\n", src);
printf("dst: %s\n", dst);
return 0;
}
'; // 必ず終端を付ける } int main(void) { const char *src = "AbC-XYZ 123"; char dst[64]; // 十分な大きさのバッファを用意 str_to_lower_copy(src, dst, sizeof(dst)); printf("src: %s\n", src); printf("dst: %s\n", dst); return 0; }
実行結果
src: AbC-XYZ 123
dst: abc-xyz 123

大文字化と小文字化のサンプル

同じ文字列から大文字化版と小文字化版を作る全体例です

C言語
#include <ctype.h>
#include <stdio.h>
#include <string.h>

void str_to_upper_copy(const char *src, char *dst, size_t dst_size) {
    if (dst_size == 0) return;
    size_t i = 0;
    for (; src[i] != '
#include <ctype.h>
#include <stdio.h>
#include <string.h>
void str_to_upper_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return;
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
dst[i] = (char)toupper((unsigned char)src[i]);
}
dst[i] = '\0';
}
void str_to_lower_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return;
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
dst[i] = (char)tolower((unsigned char)src[i]);
}
dst[i] = '\0';
}
int main(void) {
const char *src = "Hello, World! こんにちは"; // 日本語は変わらない
char upper[256];
char lower[256];
str_to_upper_copy(src, upper, sizeof(upper));
str_to_lower_copy(src, lower, sizeof(lower));
printf("src  : %s\n", src);
printf("UPPER: %s\n", upper);
printf("lower: %s\n", lower);
return 0;
}
' && i + 1 < dst_size; ++i) { dst[i] = (char)toupper((unsigned char)src[i]); } dst[i] = '
#include <ctype.h>
#include <stdio.h>
#include <string.h>
void str_to_upper_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return;
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
dst[i] = (char)toupper((unsigned char)src[i]);
}
dst[i] = '\0';
}
void str_to_lower_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return;
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
dst[i] = (char)tolower((unsigned char)src[i]);
}
dst[i] = '\0';
}
int main(void) {
const char *src = "Hello, World! こんにちは"; // 日本語は変わらない
char upper[256];
char lower[256];
str_to_upper_copy(src, upper, sizeof(upper));
str_to_lower_copy(src, lower, sizeof(lower));
printf("src  : %s\n", src);
printf("UPPER: %s\n", upper);
printf("lower: %s\n", lower);
return 0;
}
'; } void str_to_lower_copy(const char *src, char *dst, size_t dst_size) { if (dst_size == 0) return; size_t i = 0; for (; src[i] != '
#include <ctype.h>
#include <stdio.h>
#include <string.h>
void str_to_upper_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return;
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
dst[i] = (char)toupper((unsigned char)src[i]);
}
dst[i] = '\0';
}
void str_to_lower_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return;
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
dst[i] = (char)tolower((unsigned char)src[i]);
}
dst[i] = '\0';
}
int main(void) {
const char *src = "Hello, World! こんにちは"; // 日本語は変わらない
char upper[256];
char lower[256];
str_to_upper_copy(src, upper, sizeof(upper));
str_to_lower_copy(src, lower, sizeof(lower));
printf("src  : %s\n", src);
printf("UPPER: %s\n", upper);
printf("lower: %s\n", lower);
return 0;
}
' && i + 1 < dst_size; ++i) { dst[i] = (char)tolower((unsigned char)src[i]); } dst[i] = '
#include <ctype.h>
#include <stdio.h>
#include <string.h>
void str_to_upper_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return;
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
dst[i] = (char)toupper((unsigned char)src[i]);
}
dst[i] = '\0';
}
void str_to_lower_copy(const char *src, char *dst, size_t dst_size) {
if (dst_size == 0) return;
size_t i = 0;
for (; src[i] != '\0' && i + 1 < dst_size; ++i) {
dst[i] = (char)tolower((unsigned char)src[i]);
}
dst[i] = '\0';
}
int main(void) {
const char *src = "Hello, World! こんにちは"; // 日本語は変わらない
char upper[256];
char lower[256];
str_to_upper_copy(src, upper, sizeof(upper));
str_to_lower_copy(src, lower, sizeof(lower));
printf("src  : %s\n", src);
printf("UPPER: %s\n", upper);
printf("lower: %s\n", lower);
return 0;
}
'; } int main(void) { const char *src = "Hello, World! こんにちは"; // 日本語は変わらない char upper[256]; char lower[256]; str_to_upper_copy(src, upper, sizeof(upper)); str_to_lower_copy(src, lower, sizeof(lower)); printf("src : %s\n", src); printf("UPPER: %s\n", upper); printf("lower: %s\n", lower); return 0; }
実行結果
src  : Hello, World! こんにちは
UPPER: HELLO, WORLD! こんにちは
lower: hello, world! こんにちは

C言語初心者の注意点

文字列リテラルは書き換えない

文字列リテラル(例: "abc")は読み取り専用領域に置かれることがあり、書き換えると未定義動作です

書き換えたい場合はchar配列にコピーしてから行います。

C言語
#include <ctype.h>
#include <stdio.h>

int main(void) {
    // NG例(参考): 文字列リテラルの書き換えは未定義動作
    // char *p = "abc";
    // p[0] = 'A'; // 実行時エラーになる可能性がある

    // OK例: 書き換え可能な配列として保持する
    char s[] = "abc";
    s[0] = (char)toupper((unsigned char)s[0]);
    printf("%s\n", s); // "Abc"
    return 0;
}
実行結果
Abc

constを活用: 書き換えない文字列はconst char *で受けると意図が明確になります。

日本語(UTF-8)は変換しない

toupper/tolowerはバイト単位の処理であり、UTF-8の日本語やアクセント付き文字などの多バイト文字は変換されません

ASCII英字のみが対象と考えると安全です。

多言語対応の大小変換はワイド文字系(wchar_twctype.htowupper/towlower)や別ライブラリの利用を検討します。

C言語
#include <ctype.h>
#include <stdio.h>
#include <string.h>

void str_to_upper_inplace(char *s) {
    for (size_t i = 0; s[i] != '
#include <ctype.h>
#include <stdio.h>
#include <string.h>
void str_to_upper_inplace(char *s) {
for (size_t i = 0; s[i] != '\0'; ++i) {
s[i] = (char)toupper((unsigned char)s[i]);
}
}
int main(void) {
char s[] = "abc日本語XYZ";
str_to_upper_inplace(s);
printf("%s\n", s); // ASCIIだけが変わる
return 0;
}
'; ++i) { s[i] = (char)toupper((unsigned char)s[i]); } } int main(void) { char s[] = "abc日本語XYZ"; str_to_upper_inplace(s); printf("%s\n", s); // ASCIIだけが変わる return 0; }
実行結果
ABC日本語XYZ

大文字・小文字の判定は不要

事前にisupperislowerで判定する必要はありません

toupper/tolowerは、対象外の文字にはそのままの文字を返すからです。

これによりコードが簡潔で高速になります。

C言語
#include <ctype.h>
#include <stdio.h>

// 判定せずに毎回toupperを呼ぶ簡潔な方法
void to_upper_simple(char *s) {
    for (size_t i = 0; s[i] != '
#include <ctype.h>
#include <stdio.h>
// 判定せずに毎回toupperを呼ぶ簡潔な方法
void to_upper_simple(char *s) {
for (size_t i = 0; s[i] != '\0'; ++i) {
s[i] = (char)toupper((unsigned char)s[i]);
}
}
int main(void) {
char s[] = "MiXeD Case 123";
to_upper_simple(s);
printf("%s\n", s);
return 0;
}
'; ++i) { s[i] = (char)toupper((unsigned char)s[i]); } } int main(void) { char s[] = "MiXeD Case 123"; to_upper_simple(s); printf("%s\n", s); return 0; }
実行結果
MIXED CASE 123

もし判定を書く場合: 書くとしてもisupper/islowerの引数にも(unsigned char)キャストを忘れないようにします。

まとめ

touppertolowerは、英字の大文字・小文字変換を安全かつ簡単に実現する基本関数です

1文字の変換から、'\0'までのループで文字列全体を変換する方法まで理解できれば、ほとんどの用途をカバーできます。

最重要ポイントは次の3つです。

まず引数は常に(unsigned char)にキャストすること。

次にchar配列以外の文字列リテラルは書き換えないこと。

そしてUTF-8の日本語など多バイト文字は変換しないことです。

これらを守れば、初心者の方でも安全に文字の大小変換を実装できます。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!