トラック9・🔤文字列

文字コードの基礎——ASCIIとUTF-8

読む目安 約13分・ゴール:文字が数値であることを理解し、文字コードを使った計算ができる

アプリでこのトピックを学ぶ(無料・登録不要)

このトピックの要点

コンピュータは数値しか扱えません。ではなぜ文字を表示できるのか。答えは単純で、文字にも番号が振ってあるからです。「A は65番」という対応表があり、その代表が ASCII です。

#include <stdio.h>

int main(void)
{
    char c = 'A';

    printf("%c\n", c);    // A   ← 文字として表示
    printf("%d\n", c);    // 65  ← 数値として表示
    return 0;
}

同じ変数を %c で見れば文字、%d で見れば数値。char は「1バイトの小さな整数型」であり、文字はその値の解釈にすぎません。

覚えておくと得をする番号

文字値
'0' 〜 '9'48 〜 57
'A' 〜 'Z'65 〜 90
'a' 〜 'z'97 〜 122

ここで大事なのは、連続して並んでいることと、大文字と小文字がちょうど32違うことです。この2つの性質から、便利な計算が生まれます。

#include <stdio.h>

int main(void)
{
    char d = '7';

    printf("%d\n", d - '0');        // 7 ← 文字の数字を数値に変換
    printf("%c\n", 'a' - 32);       // A ← 小文字を大文字に
    printf("%d\n", 'z' - 'a' + 1);  // 26 ← アルファベットの数
    return 0;
}

d - '0' は暗記して構いません。文字 '7'(55)から '0'(48)を引くと 7。文字で入力された数字を計算に使うときの定番です。逆に、数値 7 を文字にしたければ 7 + '0' とします。

表そのものを丸暗記する必要はありません。覚えておくべきは「連続して並んでいる」「大文字と小文字は32違う」「数字は '0' から始まる」の3点だけ。具体的な値が必要になったら printf("%d\n", 'A'); で調べればすみます。

日本語はどうなっているのか

ASCIIは英数字と記号だけの表で、127番までしかありません。日本語を表すには足りないので、現在は UTF-8 という方式が広く使われています。UTF-8では、英数字は1バイトのまま、日本語のほとんどは3バイトで表されます。

printf("%zu\n", strlen("abc"));   // 3
printf("%zu\n", strlen("あいう")); // 9(3文字 × 3バイト)

strlen が数えているのはバイト数であって文字数ではありません。ここから重要な結論が出ます。

Cで日本語を1文字ずつ正確に扱うには専用の処理が必要です。初学の段階では「日本語は表示だけ、加工は英数字で」と割り切って進めるのが安全です。文字列をそのまま printf に渡して表示するぶんには、日本語でも何も問題ありません。

罠・注意

まとめ: 文字は数値。'A' は65、'0' は48で、それぞれ連続して並んでいます。c - '0' は定番、日本語はUTF-8で複数バイトです。

アプリでこのトピックを学ぶ(無料・登録不要)

確認問題

確認問題 1

printf("%d\n", 'A'); の出力は 65 でした。ここから分かることとして、正しいものはどれですか。

  1. char型は文字専用の型で、数値としては扱えない
  2. 文字にはそれぞれ番号が割り当てられていて、char は1バイトの整数型である
  3. 'A' は必ず65と決まっており、どんな文字コードでも変わらない
  4. %d を使うと文字が数値に変換されて壊れる
答えを見る

正解:B(文字にはそれぞれ番号が割り当てられていて、char は1バイトの整数型である)

char は1バイトの小さな整数型で、文字はその値の解釈にすぎません。同じ変数を %c で見れば文字、%d で見れば数値です。ASCIIでは 'A' が65ですが、値そのものを直接書くより 'A' と書くほうが読みやすく安全です。

確認問題 2

文字で書かれた数字を数値に変換するループです。空欄を埋めてください(n欄はその周が終わった時点の値)。

#include <stdio.h>

int main(void)
{
    char d[4] = "273";
    int n = 0;

    for (int i = 0; d[i] != '\0'; i++) {
        n = n * 10 + (d[i] - '0');
    }
    printf("%d\n", n);
    return 0;
}
id[i]d[i] - '0'n
0'2'2?
1'7'7?
2'3'3?
答えを見る

空欄の答え(上から順に):2、27、273

d[i] - '0' で文字の数字が数値になります('2' は50、'0' は48なので 2)。n は「これまでの値を10倍して次の桁を足す」ので、2 → 27 → 273 と育ちます。文字列を数値に変換する定番の手順です。

「文字列」の目次

  1. 文字列とはchar配列である
  2. ヌル終端 '\0' の掟
  3. 文字列リテラルと初期化
  4. string.h の主要関数
  5. 安全な文字列操作——バッファサイズの意識
  6. 文字の判定と変換(ctype.h)
  7. 文字コードの基礎——ASCIIとUTF-8
  8. 文字列処理の定石パターン

もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。

完全版の販売ページは準備中です。

ほかのトラック

📚 姉妹教材:手を動かして覚える Linux 教材 — Linuxとインフラの仕組みを地図で学ぶ

Web版