6日でできる 新C言語入門|文字コードと制御文字の基礎知識

文字は見た目、コンピュータの中では数値。
文字コードと制御文字を理解して、C言語で文字を正しく扱えるようになろう。

C言語で文字を扱うとき、画面にはAやaや1のような文字が表示されます。しかし、コンピュータの内部では、これらの文字はそのままの形で保存されているわけではありません。

コンピュータは、基本的に数値を扱う機械です。そのため、文字も数値に対応づけて管理されています。この文字と数値の対応ルールを文字コードと呼びます。

たとえば、ASCIIコードでは、大文字のAは10進数で65、小文字のaは97、数字の0は48という数値に対応しています。C言語でchar型の変数に文字を入れると、実際にはその文字に対応するコード番号が保存されます。

また、文字コードには、画面に見える文字だけでなく、改行やタブ、文字列の終端を示すNULL文字のような制御文字も含まれています。制御文字は、文字として表示するためのものではなく、表示位置を変えたり、文字列の終わりを示したりするために使われます。

C言語では、文字列の最後に入る\0も重要な制御文字のひとつです。この\0は、文字列がどこで終わるのかを示す役割を持っています。

この記事では、文字コードの基本、ASCIIコード、制御文字、C言語で文字コードを確認する方法、多言語を扱うためのShift_JISやUTF-8の考え方まで、サンプルプログラムを使いながらやさしく解説していきます。

文字コードは文字と数値の対応表

文字コードとは、文字と数値を対応づけるためのルールです。

人間はAという文字を見れば、アルファベットのAだと分かります。しかし、コンピュータの内部では、Aという形そのものではなく、対応する数値として扱われます。

ASCIIコードでは、代表的な文字は次のような数値に対応しています。

文字10進数16進数種類
A650x41英大文字
B660x42英大文字
a970x61英小文字
0480x30数字
@640x40記号
空白320x20スペース

このように、文字にはそれぞれコード番号が割り当てられています。

C言語では、char型を使って1文字を扱います。

char ch = 'A';

この場合、chには文字Aが入っているように見えますが、内部的にはAに対応する文字コードが保存されています。ASCIIコードを前提にすると、Aは65です。

char型は文字を入れる型だが中身は数値

char型は文字を扱うための型ですが、実体としては小さな整数型です。そのため、文字として表示することも、数値として表示することもできます。

たとえば、次のようにprintfの書式指定を変えることで、同じchar型の値を文字としても数値としても確認できます。

書式指定表示内容
%c文字として表示する
%d10進数の文字コードとして表示する
%X16進数の文字コードとして表示する

同じ値でも、表示のしかたによって見え方が変わります。

printf("%c\n", ch);
printf("%d\n", ch);
printf("%X\n", ch);

この考え方は、C言語で文字を扱うときにとても大切です。文字は見た目としては文字ですが、コンピュータの中では数値として処理されています。

図:文字は内部では文字コードとして扱われる

この図から分かること

この図から分かるのは、画面に表示される文字と、コンピュータ内部で扱われる数値が対応しているということです。

C言語でchar型にAを入れると、見た目はAですが、内部では対応する文字コードの値として保存されます。文字コードを理解すると、文字の比較や分類、文字列処理のしくみが分かりやすくなります。

ASCIIコードとは何か

ASCIIコードは、英数字、記号、制御文字を数値に対応づけた代表的な文字コードです。ASCIIは、基本的に0から127までの範囲で文字や制御情報を表します。

ASCIIには、画面に表示できる文字だけでなく、表示や通信を制御するための文字も含まれています。

ASCIIで扱われる主な内容は、次のように分けられます。

範囲のイメージ内容
0から31主に制御文字
32空白文字
33から126英数字や記号など表示可能な文字
127DEL制御文字

たとえば、AからZの大文字は連続したコード番号を持っています。Aが65、Bが66、Cが67というように並んでいます。小文字のaからzも同じように連続しています。

この連続性を利用すると、C言語では文字の範囲判定を簡単に書けます。

if (c >= 'A' && c <= 'Z') {
    printf("英大文字です。\n");
}

この条件では、cがAからZの範囲にあるかどうかを判定しています。文字も内部では数値なので、このような大小比較ができます。

制御文字は画面に見えない働きをする文字

文字コードには、Aや1のように画面へ表示される文字だけでなく、制御文字も含まれています。

制御文字は、画面にそのまま文字として表示するためのものではありません。改行したり、タブ位置へ移動したり、文字列の終わりを示したりするために使われます。

代表的なASCII制御文字を見てみましょう。

10進数16進数コード名前主な意味
00x00NULNull文字列の終端など
70x07BELBell警告音
80x08BSBack Spaceバックスペース
90x09HTHorizontal Tab水平タブ
100x0ALFLine Feed改行
130x0DCRCarriage Return復帰
270x1BESCEscapeエスケープ
320x20SPCSpace空白
1270x7FDELDelete削除

C言語でよく使う\nは、改行を表す制御文字です。ASCIIではLFに対応し、10進数では10です。

また、文字列の最後に入る\0は、NULに対応する制御文字です。値としては0です。

NULL文字と数字の0は違う

C言語の文字列で重要なのが、NULL文字である\0です。

\0は、文字列の終わりを示すために使われます。値としては0です。

一方、文字としての0は、数字の文字です。ASCIIコードでは48です。

表記意味文字コード
\0NULL文字、文字列の終端0
0数字の文字48

この2つは見た目が似ているため混同しやすいですが、まったく別のものです。

たとえば、文字列"ABC"は、内部では次のように並びます。

添え字0123
中身ABC\0

printfで%sを使うと、配列の先頭から順番に文字を読み、\0が見つかったところで表示を止めます。

図:制御文字は表示ではなく動作を表す

この図から分かること

この図から分かるのは、文字コードには画面に見える文字と、動作を制御するための文字があるということです。

Aや1のような文字は画面に表示されます。一方、NUL、LF、HTのような制御文字は、文字列の終端、改行、タブ移動などの役割を持っています。C言語では、\0や\nのような制御文字をよく使うため、その意味を理解しておくことが大切です。

C言語で文字と文字コードを確認する

C言語では、char型の値を文字として表示したり、数値として表示したりできます。次のプログラムでは、1つの文字について、文字、10進コード、16進コードを表示します。

プロジェクト/ファイル名: Lesson35_1/main.c

#include <stdio.h>

int main(void) {
    char ch = 'M';

    // 文字として表示する
    printf("文字: %c\n", ch);

    // 10進数の文字コードとして表示する
    printf("10進コード: %d\n", ch);

    // 16進数の文字コードとして表示する
    printf("16進コード: 0x%X\n", ch);

    return 0;
}

実行結果

文字: M
10進コード: 77
16進コード: 0x4D

このプログラムでは、chにMを代入しています。

printfで%cを使うと、chは文字として表示されます。
printfで%dを使うと、chは10進数の文字コードとして表示されます。
printfで%Xを使うと、16進数の文字コードとして表示されます。

MはASCIIコードでは10進数で77、16進数で0x4Dです。

同じchar型の値でも、書式指定を変えることで、文字としてもコード番号としても確認できます。

10進数と16進数の見方

文字コードの表では、10進数と16進数の両方がよく使われます。

表し方説明
10進数77普段の数の表し方
16進数0x4Dコンピュータ分野でよく使う表し方

C言語では、16進数を表すときに0xを付けます。

int value = 0x4D;

0x4Dは、10進数では77です。文字コードやメモリ、バイト列を扱うときは、16進数で表示したほうが見やすい場面があります。

printfで16進数を表示するには、%Xや%xを使います。

書式指定表示
%XAからFを大文字で表示
%xaからfを小文字で表示

文字コードを確認するときは、10進数と16進数の両方を見られると便利です。

文字コード表をプログラムで表示する

文字コードは、連続した数値として並んでいることがあります。たとえば、数字の0から9は、ASCIIコード上で連続しています。

次のプログラムでは、数字文字0から9までを順番に表示し、それぞれの文字コードを確認します。

プロジェクト/ファイル名: Lesson35_2/main.c

#include <stdio.h>

int main(void) {
    char c;

    // 数字文字0から9までの文字と文字コードを表示する
    for (c = '0'; c <= '9'; c++) {
        printf("%c: %d  ", c, c);
    }

    printf("\n");

    return 0;
}

実行結果

0: 48  1: 49  2: 50  3: 51  4: 52  5: 53  6: 54  7: 55  8: 56  9: 57

このプログラムでは、for文のカウンタとしてchar型のcを使っています。

for (c = '0'; c <= '9'; c++)

文字0から文字9までが連続した文字コードになっているため、c++で次の文字へ進めます。

注意したいのは、文字0と数値0は違うという点です。文字0のASCIIコードは48です。数値としての0とは別の意味になります。

表記意味
0整数値の0
0数字の文字
\0NULL文字、値は0

C言語では、この違いを意識しておくと、文字処理や文字列処理が理解しやすくなります。

文字コードを使った文字の判定

文字コードを理解すると、入力された文字が英大文字なのか、英小文字なのか、数字なのかを判定しやすくなります。

たとえば、ASCIIコードでは、AからZ、aからz、0から9がそれぞれ連続した範囲に並んでいます。

範囲意味
AからZ英大文字
aからz英小文字
0から9数字文字

C言語では、次のように文字同士を比較できます。

if (c >= 'A' && c <= 'Z') {
    printf("英大文字です。\n");
}

文字も内部では数値なので、範囲比較が可能です。

数値の65や90を直接使うこともできますが、学習や実務では、AやZのような文字を使って条件を書くほうが意味を読み取りやすくなります。

入力された文字を判定するプログラム

次のプログラムでは、ユーザーが入力した1文字を調べ、英大文字、英小文字、数字文字、その他の文字に分類します。

プロジェクト/ファイル名: Lesson35_3/main.c

#include <stdio.h>

int main(void) {
    char c;

    printf("1文字入力してください: ");
    scanf(" %c", &c);

    // 英大文字かどうかを判定する
    if (c >= 'A' && c <= 'Z') {
        printf("英大文字です。\n");
    }
    // 英小文字かどうかを判定する
    else if (c >= 'a' && c <= 'z') {
        printf("英小文字です。\n");
    }
    // 数字文字かどうかを判定する
    else if (c >= '0' && c <= '9') {
        printf("数字文字です。\n");
    }
    // どの範囲にも当てはまらない場合
    else {
        printf("その他の文字です。\n");
    }

    return 0;
}

実行結果

1文字入力してください: G
英大文字です。

このプログラムでは、scanfで1文字を入力し、cに保存しています。

scanf(" %c", &c);

%cの前に空白を入れているのは、直前の入力で残った改行などを読み飛ばしやすくするためです。1文字入力を扱うときによく使われる書き方です。

その後、if文で文字の範囲を判定しています。

if (c >= 'A' && c <= 'Z')

この条件は、cがAからZの範囲にあるかどうかを調べています。文字コードの並びを利用した判定です。

Visual Studioでscanfを使う場合、環境設定によって警告が表示されることがあります。学習用として動作確認する場合は、必要に応じてSDLチェックの設定も確認しておきましょう。

文字コードを使うときは読みやすさも大切

文字コードで文字を判定するとき、数値を直接書くこともできます。

if (c >= 65 && c <= 90) {
    printf("英大文字です。\n");
}

これはASCIIコードを知っていれば意味が分かります。しかし、コードを読んだ人にとっては、65や90が何を表しているのかすぐには分かりにくい場合があります。

そのため、次のように文字で書くほうが読みやすくなります。

if (c >= 'A' && c <= 'Z') {
    printf("英大文字です。\n");
}

この書き方なら、AからZの範囲を判定していることがすぐ分かります。

書き方特徴
c >= 65 && c <= 90文字コードの数値を直接使う
c >= 'A' && c <= 'Z'文字の範囲として読みやすい

文字コードを理解することは大切ですが、プログラムを書くときは読みやすさも意識しましょう。

日本語や多言語を扱う文字コード

ASCIIコードは、英数字や基本的な記号を扱うための文字コードです。そのため、日本語のひらがな、カタカナ、漢字などはASCIIだけでは表現できません。

日本語や世界中の文字を扱うために、さまざまな文字コードが使われてきました。

文字コード概要特徴
Shift_JIS日本語環境で広く使われてきた文字コードWindows日本語環境でよく見かける
EUC-JPUNIX系環境で使われてきた日本語文字コード日本語を複数バイトで表す
UTF-8Unicodeをもとにした文字コード世界中の文字を扱いやすく、ASCIIとの互換性がある

現在は、さまざまな環境でUTF-8が広く使われています。UTF-8は英数字の範囲ではASCIIと互換性があり、日本語や多言語の文字も表現できます。

ただし、C言語のchar型は基本的に1バイト単位のデータを扱います。UTF-8の日本語文字は複数バイトで表されるため、1文字がchar 1個に収まるとは限りません。

たとえば、英字のAは1バイトで表せますが、日本語のあはUTF-8では複数バイトで表されます。このため、日本語文字を1文字ずつ正確に処理したい場合は、単純なchar配列だけでは扱いが難しくなることがあります。

図:ASCIIとUTF-8の考え方の違い

この図から分かること

この図から分かるのは、ASCIIでは主に英数字や記号を1バイトのコードとして扱うのに対し、UTF-8では日本語などの文字が複数バイトになることがあるという点です。

C言語のchar型は1バイト単位でデータを扱うため、英数字の処理は比較的分かりやすいです。一方、日本語のような多バイト文字を1文字単位で扱う場合は、文字コードの仕組みを意識する必要があります。

UTF-8とC言語で注意したいこと

UTF-8は、世界中の文字を扱うために広く使われている文字コードです。英数字や基本的な記号についてはASCIIと同じコードになるため、ASCIIとの互換性があります。

しかし、日本語のような文字は、UTF-8では複数バイトで表現されます。C言語でchar配列として扱う場合、配列の1要素が1文字を表すとは限りません。

たとえば、次のような文字列を考えます。

char text[] = "ABC";

この場合、A、B、Cはそれぞれ1バイトで扱いやすいです。

一方、日本語を含む文字列では、見た目の文字数とバイト数が一致しない場合があります。

char text[] = "あい";

このような文字列では、text[0]が文字あ全体を表すとは限りません。UTF-8では、あが複数バイトで表されるためです。

文字の種類char配列での見え方
ASCIIの英数字1文字が1バイトに対応しやすい
日本語などの多バイト文字1文字が複数バイトになることがある

C言語で多言語文字列を正確に処理したい場合は、文字コードやライブラリの扱いを理解する必要があります。まずは、char型は1バイト単位であり、日本語などは複数バイトになることがあると覚えておくとよいです。

制御文字を理解すると文字列処理が分かりやすくなる

C言語では、制御文字が文字列処理の中でよく登場します。

特に重要なのは、次の3つです。

表記意味よく使う場面
\0NULL文字、文字列の終端C言語の文字列
\n改行printfで行を変える
\tタブ表示位置をそろえる

\0は、文字列がどこで終わるかを示します。
\nは、表示を次の行へ移動します。
\tは、表示位置をタブ幅に合わせて進めます。

これらは画面にそのまま見える文字というより、表示や処理を制御するための文字です。

文字コードを学ぶとC言語の文字処理が理解しやすくなる

文字コードは、文字と数値を対応づけるためのルールです。C言語では、char型の変数に文字を代入すると、内部では文字コードとして保存されます。

ASCIIコードでは、Aは65、aは97、数字の0は48のように対応しています。また、NUL、LF、HTのような制御文字も文字コードに含まれています。

制御文字は、文字として表示するだけでなく、改行、タブ、文字列の終端などの役割を持ちます。特に\0はC言語の文字列の終わりを示すため、文字列を理解するうえで欠かせません。

さらに、日本語や多言語を扱う場合は、Shift_JIS、EUC-JP、UTF-8のような文字コードの存在も重要です。現在よく使われるUTF-8では、日本語のような文字が複数バイトで表されるため、char型1つが必ず1文字を表すとは限りません。

文字コードを理解すると、C言語で文字を表示するだけでなく、文字の判定、文字列の終端、多バイト文字の注意点まで見通しやすくなります。まずはASCIIコードと制御文字の基本から押さえ、C言語の文字処理に慣れていきましょう。