C言語で英字を扱うとき、「大文字と小文字をきれいにそろえる」ことはとても大切です。
ユーザー名のチェックや、検索のときの大小文字無視、見た目をそろえた表示など、さまざまな場面で役に立ちます。
本記事では、C言語初心者の方を対象に、toupperとtolowerという標準ライブラリ関数を使って、英字の大文字・小文字を自在に変換する方法を、サンプルコードつきで丁寧に解説します。
toupper, tolowerとは
toupper, tolowerで何ができるか
C言語には、文字の種類を判定したり、文字を変換したりするための関数が標準ライブラリとして用意されています。
その中でも英字の大文字・小文字変換に特化したものがtoupperとtolowerです。
toupper
小文字の英字を対応する大文字に変換します。例えば'a'を'A'にします。tolower
大文字の英字を対応する小文字に変換します。例えば'Z'を'z'にします。
どちらの関数も、英字以外の文字(数字や記号、日本語など)が来た場合はそのまま同じ文字を返すという性質があります。
この性質のおかげで、文字列の中身をまるごと変換しても、英字以外が壊れないというメリットがあります。
1文字ずつ処理する関数であることを理解しよう
toupperとtolowerは、「1回の呼び出しで1文字だけ」を処理する関数です。
ここでいう1文字とは、C言語のchar型やint型で表される1つの文字コードを意味します。
したがって、次のような誤解をしないことが重要です。
- 誤り: 「
toupperに文字列を渡せば、文字列全体が大文字になる」 - 正しい理解: 「
toupperは1文字だけ変換する。文字列全体を変換したいなら、ループで1文字ずつ呼び出す」
この「1文字ずつ処理する」という感覚を身につけると、後でfor文やwhile文と組み合わせたときに、とても理解しやすくなります。
文字列と文字(char)の違いを意識しよう
C言語初心者が混乱しやすいポイントとして、「文字」と「文字列」の違いがあります。
toupperやtolowerを正しく使うためにも、この違いをしっかり理解しておくことが大切です。
- 文字
1つの記号や文字を表すものです。C言語ではchar型で表現され、'A'のようにシングルクォートで囲みます。 - 文字列
複数の文字が並んだものです。C言語ではchar型の配列として扱われ、"Hello"のようにダブルクォートで囲みます。末尾には自動的に'\0'(ヌル文字)が付きます。
次の表で整理すると、違いがはっきりします。
| 種類 | 例 | 型 | 囲み記号 | 説明 |
|---|---|---|---|---|
| 文字 | 'A' | char | シングルクォート | 1つの文字 |
| 文字列 | "A" | char[] | ダブルクォート | 2文字(Aと終端'\0') |
toupper, tolowerは「文字(1文字)」に対して使う関数です。
文字列を扱う場合は、配列の各要素str[i]という形で、1文字ずつ取り出して渡します。
toupper, tolowerの使い方
ヘッダファイルctype.hをインクルードする
toupperとtolowerを使うためには、標準ヘッダファイルであるctype.hをインクルードする必要があります。
#include <stdio.h> /* 入出力関数の宣言 */
#include <ctype.h> /* toupper, tolower, isalpha などの宣言 */
#include <ctype.h>を書き忘れると、コンパイル時に「宣言されていない関数を使っている」という警告やエラーが出ることがあります。
C言語では、使う関数の宣言が入ったヘッダファイルを必ずインクルードするというルールを覚えておきましょう。
toupperの基本的な使い方
toupperの基本的な使い方は、とてもシンプルです。
引数に1文字を渡し、その戻り値を受け取るだけです。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char ch = 'a'; /* 小文字の'a' */
char upper;
/* toupperはintを返すが、ここではcharに代入して利用 */
upper = (char)toupper((unsigned char)ch);
printf("元の文字: %c\n", ch);
printf("大文字に変換: %c\n", upper);
return 0;
}
元の文字: a
大文字に変換: A
ここでのポイントは、元の変数chは変化せず、変換後の文字を別の変数upperに代入していることです。
もちろん、同じ変数に上書きしても構いません。
ch = (char)toupper((unsigned char)ch); /* ch自身を上書き */
tolowerの基本的な使い方
tolowerも使い方は同様で、1文字を小文字に変換します。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char ch = 'Z'; /* 大文字の'Z' */
char lower;
/* tolowerで小文字に変換 */
lower = (char)tolower((unsigned char)ch);
printf("元の文字: %c\n", ch);
printf("小文字に変換: %c\n", lower);
return 0;
}
元の文字: Z
小文字に変換: z
このように、toupperは「大文字化」、tolowerは「小文字化」という役割を持ちます。
戻り値と引数の型(intとchar)に注意する
C言語のtoupperとtolowerの正式な宣言は、標準では次のようになっています。
int toupper(int c);
int tolower(int c);
つまり、引数の型も戻り値の型もintです。
しかし、実際にはcharで扱うことが多いので、初心者の方には少しわかりにくいかもしれません。
ポイントを整理すると次のようになります。
- 引数
cには、unsigned charに変換可能な値か、またはEOFを渡す、という規則になっています。 - 戻り値は変換後の文字コードを表すint値なので、
charに代入して使うときはキャストするのが安全です。
安全な書き方の例は次のようになります。
char ch = 'a';
ch = (char)toupper((unsigned char)ch);
なぜわざわざ(unsigned char)を付けるのかという疑問が湧くかもしれません。
これは、環境によってはcharが符号付きになるため、負の値が渡るとtoupperの動作が未定義になる可能性があるからです。
初心者のうちは、「文字を渡すときは(unsigned char)を付けるのが安全な書き方」と覚えておくとよいです。
アルファベット以外の文字が来たときの動き
toupperとtolowerは、英字以外の文字を変換しません。
具体的には、数字や記号、日本語などが引数として渡された場合、そのまま同じ値を返します。
次のサンプルで動きを確認してみます。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char chars[] = { 'a', 'Z', '5', '!', 'あ' };
int i;
for (i = 0; i < 5; i++) {
char c = chars[i];
char up = (char)toupper((unsigned char)c);
char low = (char)tolower((unsigned char)c);
printf("元: %c, toupper: %c, tolower: %c\n", c, up, low);
}
return 0;
}
元: a, toupper: A, tolower: a
元: Z, toupper: Z, tolower: z
元: 5, toupper: 5, tolower: 5
元: !, toupper: !, tolower: !
元: あ, toupper: あ, tolower: あ
このように、アルファベット以外は変わらずにそのままであることがわかります。
この性質のおかげで、文字列全体を一気に処理しても、英字以外は安全に残しておけるという利点があります。
if文と組み合わせた大文字・小文字変換テクニック
if文で英字かどうかをチェックする方法
大文字・小文字の変換を行う前に、「その文字が英字かどうか」を判定したくなることがあります。
例えば、英字だけを変換して、数字や記号は触らないという処理をしたい場合です。
このときに役に立つのが、同じctype.hに含まれているisalpha関数です。
#include <ctype.h>
int isalpha(int c); /* 英字なら0以外、英字でなければ0 を返す */
使い方の例を示します。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char c = 'A';
if (isalpha((unsigned char)c)) {
printf("%c は英字です。\n", c);
} else {
printf("%c は英字ではありません。\n", c);
}
return 0;
}
A は英字です。
このif (isalpha((unsigned char)c))という形は、「英字ならtrue、そうでなければfalse」という意味になり、toupperやtolowerと組み合わせると、とてもきれいなコードを書けます。
toupperで大文字だけに揃えるサンプルコード
次に、文字列の中にある英字をすべて大文字にそろえるサンプルを示します。
ここではif文とisalphaを組み合わせて、英字だけを大文字に変換します。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "Hello, C Language! 123";
int i = 0;
printf("変換前: %s\n", str);
while (str[i] != '#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "Hello, C Language! 123";
int i = 0;
printf("変換前: %s\n", str);
while (str[i] != '\0') { /* 文字列の終端'\0'までループ */
unsigned char c = (unsigned char)str[i];
/* 英字の場合のみ大文字に変換する */
if (isalpha(c)) {
str[i] = (char)toupper(c);
}
i++;
}
printf("大文字に揃えた後: %s\n", str);
return 0;
}
') { /* 文字列の終端'#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "Hello, C Language! 123";
int i = 0;
printf("変換前: %s\n", str);
while (str[i] != '\0') { /* 文字列の終端'\0'までループ */
unsigned char c = (unsigned char)str[i];
/* 英字の場合のみ大文字に変換する */
if (isalpha(c)) {
str[i] = (char)toupper(c);
}
i++;
}
printf("大文字に揃えた後: %s\n", str);
return 0;
}
'までループ */
unsigned char c = (unsigned char)str[i];
/* 英字の場合のみ大文字に変換する */
if (isalpha(c)) {
str[i] = (char)toupper(c);
}
i++;
}
printf("大文字に揃えた後: %s\n", str);
return 0;
}
変換前: Hello, C Language! 123
大文字に揃えた後: HELLO, C LANGUAGE! 123
この例では、アルファベット以外の文字(カンマ、空白、数字など)はそのままで、英字だけが大文字になっていることが確認できます。
tolowerで小文字だけに揃えるサンプルコード
同じ考え方で、文字列の英字をすべて小文字にそろえることもできます。
こちらもisalphaで英字かどうかをチェックしてからtolowerを使います。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "Hello, C Language! 123";
int i = 0;
printf("変換前: %s\n", str);
while (str[i] != '#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "Hello, C Language! 123";
int i = 0;
printf("変換前: %s\n", str);
while (str[i] != '\0') {
unsigned char c = (unsigned char)str[i];
/* 英字の場合のみ小文字に変換する */
if (isalpha(c)) {
str[i] = (char)tolower(c);
}
i++;
}
printf("小文字に揃えた後: %s\n", str);
return 0;
}
') {
unsigned char c = (unsigned char)str[i];
/* 英字の場合のみ小文字に変換する */
if (isalpha(c)) {
str[i] = (char)tolower(c);
}
i++;
}
printf("小文字に揃えた後: %s\n", str);
return 0;
}
変換前: Hello, C Language! 123
小文字に揃えた後: hello, c language! 123
このように、toupperとtolowerはほぼ対称的な関数であり、大文字で統一したいか、小文字で統一したいかによって使い分けます。
if文+toupper, tolowerで簡単な文字チェックを作る
if文とtoupper、tolowerを組み合わせることで、簡単な「文字チェック」を作ることもできます。
ここでは、入力された文字が「y」または「Y」なら「はい」と判定するプログラムを例にします。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char ch;
printf("続行しますか?(y/n): ");
scanf(" %c", &ch); /* 先頭のスペースで前の改行を読み飛ばす */
/* 入力文字を大文字に変換してから比較することで、
'y' と 'Y' の両方に対応できる */
if ((char)toupper((unsigned char)ch) == 'Y') {
printf("はい が選ばれました。\n");
} else {
printf("いいえ または それ以外が選ばれました。\n");
}
return 0;
}
続行しますか?(y/n): y
はい が選ばれました。
続行しますか?(y/n): Y
はい が選ばれました。
このように、比較の前に一度だけ大文字または小文字にそろえることで、「大小文字を区別しないチェック」を簡単に実現できます。
これは、ユーザー入力の判定や、キーワード判定などでとても役に立つテクニックです。
文字列操作とctype.hの基礎力アップ
文字列全体を大文字・小文字に変換するループ処理
ここまでの内容を踏まえると、文字列全体を大文字または小文字に変換する処理は、while文やfor文で'\0'までループしながら1文字ずつtoupperやtolowerを呼び出す、という形になります。
大文字に統一する例を、for文で書いてみます。
#include <stdio.h>
#include <ctype.h>
void to_upper_str(char str[])
{
int i;
for (i = 0; str[i] != '#include <stdio.h>
#include <ctype.h>
void to_upper_str(char str[])
{
int i;
for (i = 0; str[i] != '\0'; i++) {
/* 1文字ずつ大文字に変換していく */
str[i] = (char)toupper((unsigned char)str[i]);
}
}
void to_lower_str(char str[])
{
int i;
for (i = 0; str[i] != '\0'; i++) {
/* 1文字ずつ小文字に変換していく */
str[i] = (char)tolower((unsigned char)str[i]);
}
}
int main(void)
{
char s1[] = "AbcD123!";
char s2[] = "AbcD123!";
printf("元の文字列 s1: %s\n", s1);
printf("元の文字列 s2: %s\n", s2);
to_upper_str(s1);
to_lower_str(s2);
printf("大文字に統一した s1: %s\n", s1);
printf("小文字に統一した s2: %s\n", s2);
return 0;
}
'; i++) {
/* 1文字ずつ大文字に変換していく */
str[i] = (char)toupper((unsigned char)str[i]);
}
}
void to_lower_str(char str[])
{
int i;
for (i = 0; str[i] != '#include <stdio.h>
#include <ctype.h>
void to_upper_str(char str[])
{
int i;
for (i = 0; str[i] != '\0'; i++) {
/* 1文字ずつ大文字に変換していく */
str[i] = (char)toupper((unsigned char)str[i]);
}
}
void to_lower_str(char str[])
{
int i;
for (i = 0; str[i] != '\0'; i++) {
/* 1文字ずつ小文字に変換していく */
str[i] = (char)tolower((unsigned char)str[i]);
}
}
int main(void)
{
char s1[] = "AbcD123!";
char s2[] = "AbcD123!";
printf("元の文字列 s1: %s\n", s1);
printf("元の文字列 s2: %s\n", s2);
to_upper_str(s1);
to_lower_str(s2);
printf("大文字に統一した s1: %s\n", s1);
printf("小文字に統一した s2: %s\n", s2);
return 0;
}
'; i++) {
/* 1文字ずつ小文字に変換していく */
str[i] = (char)tolower((unsigned char)str[i]);
}
}
int main(void)
{
char s1[] = "AbcD123!";
char s2[] = "AbcD123!";
printf("元の文字列 s1: %s\n", s1);
printf("元の文字列 s2: %s\n", s2);
to_upper_str(s1);
to_lower_str(s2);
printf("大文字に統一した s1: %s\n", s1);
printf("小文字に統一した s2: %s\n", s2);
return 0;
}
元の文字列 s1: AbcD123!
元の文字列 s2: AbcD123!
大文字に統一した s1: ABCD123!
小文字に統一した s2: abcd123!
このように、「1文字関数をループで回す」というパターンは、C言語で文字列を扱うときの基本中の基本です。
配列とループの感覚を身につけるためにも、何度か自分で書いてみることをおすすめします。
scanf, fgetsで読んだ文字列にtoupper, tolowerを適用する
実際のプログラムでは、scanfやfgetsを使ってユーザーから文字列を入力してもらい、それに対して大小文字変換を行うことがよくあります。
ここでは、fgetsを使った安全な読み込みと、その後にtoupperを適用する例を紹介します。
#include <stdio.h>
#include <ctype.h>
#define BUF_SIZE 100
int main(void)
{
char buf[BUF_SIZE];
int i;
printf("文字列を入力してください: ");
/* fgetsは空白を含む1行を読み込む。末尾に'\n'が入ることに注意 */
if (fgets(buf, BUF_SIZE, stdin) == NULL) {
printf("入力エラー\n");
return 1;
}
/* 文字列全体を大文字に変換する */
for (i = 0; buf[i] != '#include <stdio.h>
#include <ctype.h>
#define BUF_SIZE 100
int main(void)
{
char buf[BUF_SIZE];
int i;
printf("文字列を入力してください: ");
/* fgetsは空白を含む1行を読み込む。末尾に'\n'が入ることに注意 */
if (fgets(buf, BUF_SIZE, stdin) == NULL) {
printf("入力エラー\n");
return 1;
}
/* 文字列全体を大文字に変換する */
for (i = 0; buf[i] != '\0'; i++) {
buf[i] = (char)toupper((unsigned char)buf[i]);
}
printf("大文字に変換した結果: %s\n", buf);
return 0;
}
'; i++) {
buf[i] = (char)toupper((unsigned char)buf[i]);
}
printf("大文字に変換した結果: %s\n", buf);
return 0;
}
文字列を入力してください: Hello World! 123
大文字に変換した結果: HELLO WORLD! 123
scanf(“%s”, …)では空白で区切られてしまいますが、fgetsを使えばスペースを含んだ1行全体を扱えます。
読み込んだ後は、これまでと同じようにfor文やwhile文で'\0'までループしながらtoupper/tolowerを適用すればよいです。
toupper, tolowerと他のctype.h関数(isalphaなど)の組み合わせ
ctype.hには、文字の種類を判定する関数が多数含まれています。
代表的なものをいくつか挙げると、次のようになります。
| 関数名 | 役割 | 戻り値 |
|---|---|---|
isalpha | 英字かどうか判定 | 英字なら0以外 |
isdigit | 数字かどうか判定 | 数字なら0以外 |
isalnum | 英数字かどうか判定 | 英数字なら0以外 |
isspace | 空白文字かどうか判定 | 空白なら0以外 |
isupper | 大文字かどうか判定 | 大文字なら0以外 |
islower | 小文字かどうか判定 | 小文字なら0以外 |
これらをtoupper/tolowerと組み合わせることで、柔軟な文字列処理が可能になります。
例えば、英字だけを大文字にし、数字はそのまま、空白は別の文字に置き換えるといった処理も簡単に書けます。
次の例では、isalphaとisdigitを使って、文字の種類ごとに処理を変えています。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "Abc 123 xYz!";
int i;
printf("元の文字列: %s\n", str);
for (i = 0; str[i] != '#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "Abc 123 xYz!";
int i;
printf("元の文字列: %s\n", str);
for (i = 0; str[i] != '\0'; i++) {
unsigned char c = (unsigned char)str[i];
if (isalpha(c)) {
/* 英字は大文字に変換 */
str[i] = (char)toupper(c);
} else if (isdigit(c)) {
/* 数字はそのまま残す(ここでは何もしない) */
} else if (isspace(c)) {
/* 空白はアンダースコアに置き換え */
str[i] = '_';
} else {
/* その他の記号などはそのまま */
}
}
printf("変換後の文字列: %s\n", str);
return 0;
}
'; i++) {
unsigned char c = (unsigned char)str[i];
if (isalpha(c)) {
/* 英字は大文字に変換 */
str[i] = (char)toupper(c);
} else if (isdigit(c)) {
/* 数字はそのまま残す(ここでは何もしない) */
} else if (isspace(c)) {
/* 空白はアンダースコアに置き換え */
str[i] = '_';
} else {
/* その他の記号などはそのまま */
}
}
printf("変換後の文字列: %s\n", str);
return 0;
}
元の文字列: Abc 123 xYz!
変換後の文字列: ABC_123_XYZ!
このように、ctype.hの関数群は組み合わせて使うことで威力を発揮します。
toupperやtolowerだけでなく、文字の種別判定関数も一緒に覚えておくと、文字操作の幅が大きく広がります。
C言語初心者が覚えておきたい文字操作のポイント
最後に、C言語初心者の方がtoupperやtolowerを使いこなすために、特に意識しておきたいポイントをまとめます。
まず、「文字」と「文字列」の違いを常に意識することが重要です。
1文字はchar型で、シングルクォート'A'で表します。
一方、文字列はcharの配列であり、ダブルクォート"ABC"で表現し、末尾には'\0'が必ず付きます。
toupper/tolowerは1文字ずつに対して使う関数なので、文字列に対しては配列の添字で1文字ずつアクセスするという形になります。
また、標準ライブラリを正しくインクルードする習慣も大切です。
ctype.hをインクルードすることで、コンパイラが関数の宣言を認識し、型のチェックをしてくれます。
ヘッダを忘れると、思わぬ不具合や警告の原因になります。
さらに、ループ処理と終端文字'\0'の扱いにも早いうちから慣れておきましょう。
文字列の処理は「終端'\0'に出会うまで1文字ずつ進める」というパターンが基本となります。
for文でもwhile文でもかまいませんが、どちらでも書けるようになると理解が深まります。
最後に、大小文字を意識しない比較やチェックという発想を身につけると実用性が一気に高まります。
入力文字を先にtoupperまたはtolowerでそろえてから比較することで、「y」「Y」のどちらでもOKといった柔軟な処理が簡単に書けます。
このテクニックは、小さなプログラムから本格的なアプリケーションまで、あらゆる場面で役に立つ考え方です。
まとめ
toupperとtolowerは、C言語で英字の大文字・小文字を自在に変換できる非常に基本的で重要な関数です。
1文字ずつ処理する関数であること、文字と文字列の違い、そしてctype.hをインクルードする必要があることを理解しておけば、ループと組み合わせて文字列全体を簡単に変換できます。
また、isalphaなどの判定系関数と組み合わせることで、英字だけを変換したり、大小文字を意識しない入力チェックを実現したりできます。
この記事で紹介したサンプルコードを実際に打ち込んで動かしながら、文字操作の基礎力をしっかり身につけていきましょう。
