C言語入門|配列とString型の正体

配列の学習もひと通り終わって、
「よし、これで配列は理解できたぞ!」
……と言いたいところですが、ここで立ち止まっている人も多いはずです。

「配列の宣言って、どうしてこんな書き方なんだろう?」
「String型って、結局なにものなんだろう?」

実はこの2つ、
同じ正体 を持っています。

この章では、
配列とString型の本当の姿 をひもときながら、
これまで守ってきたルールの意味をスッキリ整理していきます。

配列宣言がしっくりこない理由

たとえば、次の配列宣言。

int values[10];

これを初めて見たとき、
「int 型の values[10] という変数?」
と感じた人も多いのではないでしょうか。

でも、正確にはこれは、

  • int 型の変数が10個ある
    のではなく
  • int[10] 型の変数 values が1つある

という意味でしたね。

そう考えると、

int[10] values;

と書きたくなる気持ちも、よく分かります。

残念ながら、これはC言語の文法上できません。
でも、このモヤモヤを少しだけ解消してくれる仕組みがあります。

typedef で配列型に別名をつける

その仕組みが、typedef です。

typedef は、
既存の型に別名を与える命令 でしたね。

ここで、配列型に別名をつけてみましょう。

typedef int ScoreList[10];

この1行は、

  • int 型に別名をつけている
    のではなく
  • int[10] 型に ScoreList という別名をつけている

という意味になります。

別名を使った配列宣言

先ほどの typedef を使うと、
配列宣言は次のように書けます。

プロジェクト名:7-11-1 ソースファイル名: sample7-11-1.c

#include <stdio.h>

int main(void)
{
    typedef int ScoreList[10];
    ScoreList scores;

    scores[2] = 90;
    printf("%d\n", scores[2]);

    return 0;
}

この scores は、

int scores[10];

とまったく同じものです。

型名がひとまとまりになるので、
「これは10個のintを持つ配列なんだな」
と、頭の中でイメージしやすくなります。

String型という「おまじない」の正体

さて、ここで多くの人が
「あっ!」
と気づくポイントがあります。

あの有名な一文です。

typedef char String[1024];

これまで何となく
「文字列用の特別な型」
として使ってきた String 型。

でも、配列を理解した今なら、
もう意味がはっきり分かりますね。

String型はただのchar配列

この typedef の意味は、とてもシンプルです。

項目内容
要素の型char
要素数1024
別名String

つまり、

String型の正体は
要素数1024のchar配列型

ということです。

これまで扱ってきた String 型は、
単なる配列の別名 にすぎません。

String型から1文字ずつ取り出せる理由

String 型が配列だと分かると、
次のコードも自然に理解できます。

プロジェクト名:7-11-2 ソースファイル名: sample7-11-2.c

#include <stdio.h>

typedef char String[1024];

int main(void)
{
    String message = "CODE";

    printf("%c\n", message[0]);  // 'C'
    printf("%c\n", message[1]);  // 'O'
    printf("%c\n", message[2]);  // 'D'
    printf("%c\n", message[3]);  // 'E'

    return 0;
}

message[0] や message[1] は、
char配列の各要素 にすぎません。

String 型だから特別なのではなく、
配列だから1文字ずつ取り出せる。
それだけの話だったんですね。

String型の「ルール」の正体に気づこう

ここで、これまで守ってきた
String型のルールを思い出してください。

  • 初期化以外で = 代入をしてはいけない。
  • 計算や連結に使ってはならない。
  • 演算子で比較してはならない。

なぜ、こんなに制限が多かったのでしょうか。

答えは、とてもシンプルです。

禁止されていた操作は配列の禁止事項そのもの

代入・計算・比較。

これらはすべて、
配列に対して行ってはいけない操作 でした。

String 型は配列です。
だから、

  • 配列として禁止されている操作
  • String型でも禁止されている操作

という関係になっていたわけです。

つまり、
String型のルールは「おまじない」ではなく、
ちゃんとした理由のある安全装置 だったのです。

文字列の表示だけが許されている理由

「でも、printfで文字列は表示できましたよね?」

そのとおりです。
これは、printf 命令の 特別扱い です。

printf("%s\n", message);

%s を使うと、

  • char配列を受け取って
  • 先頭から1文字ずつ取り出し
  • 終端まで順番に表示する

という処理を、printf が内部でやってくれます。

配列をそのまま表示しているのではなく、
1文字ずつ処理している からこそ、
例外的に許されているのです。

まとめ:String型は配列だった

最後に、この章の要点をまとめます。

  • 配列型は typedef で別名をつけられる。
  • String型は char配列型の別名にすぎない。
  • String型のルールは配列のルールそのもの
  • 特別なのは printf の %s だけ

正体が分かると、
「意味不明だった制約」が
「なるほど納得」に変わります。

C言語は、
理解が深まるほど楽しくなる言語です。

さあ、次は
配列と文字列のさらに深い核心
に踏み込んでいきましょう 😊