配列

同じデータ型の変数をまとめて扱う

変数を使うと、値を一時的に保存しておくことができます。
変数はプログラミングには欠かせないものですが、数が多くなってくると管理が大変になってきます。
配列を使えば、同じような用途の変数をひとつにまとめることができます。

例えば以下のようなコードがあるとします。

#include <stdio.h>

int main()
{
    int kazu1, kazu2, kazu3;
    kazu1 = 10;
    kazu2 = 20;
    kazu3 = 30;

    printf("kazu1: %d\nkazu2: %d\nkazu3: %d",
        kazu1, kazu2, kazu3);

    getchar();
}
10
20
30

配列を使用しない場合、必要な数だけ変数を用意する必要があります。
三つくらいならば問題なくても、時には100や1000などの膨大な数の変数が必要になることがあります。
それをひとつひとつ宣言していては大変です。

配列を使うと、以下のように書けます。

#include <stdio.h>

int main()
{
    int arrKazu[3];
    arrKazu[0] = 10;
    arrKazu[1] = 20;
    arrKazu[2] = 30;

    printf("arrKazu[0]: %d\narrKazu[1]: %d\narrKazu[2]: %d",
        arrKazu[0], arrKazu[1], arrKazu[2]);

    getchar();
}
arrKazu[0]: 10
arrKazu[1]: 20
arrKazu[2]: 30

5行目で配列の使用を宣言しています。
配列は、同じデータ型を持つ変数をまとめて扱うことができます。

配列の宣言

配列の宣言は、変数と同じようにまず使用したいデータ型を書きます。
配列名は自由に決定できます。

変数との違いは、最後に[]記号を書き、その中に配列のサイズを指定することです。

配列のサイズ

配列のサイズとは、その配列に保存しておけるデータの数です。
「int arr[3];」と宣言した場合は、配列arrは0~2の3つの整数(int型)のデータを保存できます。

配列の開始番号は0から始まるという点に注意しましょう。
サンプルコードでは、配列のそれぞれの番号は0、1、2となり、配列の宣言で書いた数字から-1した数が最大値となります。

配列の各要素へのアクセス

配列に値を代入したり、値を取り出すには配列の先頭からの番号を[]内の数字で指定します。
この記号を添字演算子(そえじえんざんし)といいます。

添字演算子の中に記述する数字を添え字、indexと呼びます。
また、配列の各番号に保存される値を配列の要素と呼びます。

「arr[1] = 20」ならば、2番目の要素に20の値を代入できます。
「arr[0] = arr[1]」ならば、2番目の要素の値を先頭の要素にコピーできます。

以下のように配列自体に別の配列を代入することはできません。

int arr1[3];
int arr2[3];

//エラー  
arr1 = arr2;

配列全体のコピーをしたい場合は、各要素をひとつひとつ代入していく必要があります。

arr1[0] = arr2[0];
arr1[1] = arr2[1];
arr1[2] = arr2[2];

要素数が多くなると大変な作業になりますが、このような場合はループ文を用いれば簡単にできます。
(ループ文については別途説明します)

範囲外アクセス

配列に、その配列のサイズよりも大きな値の添え字を指定すると配列の範囲外へのアクセスが発生します。
これはどのような動作になるのかが保障されないので範囲外アクセスは行わないように注意してください。

int arr[3];

//範囲外アクセス!
arr[100] = 1;

//これも範囲外アクセス!
arr[3] = 1;

配列の初期化あれこれ

配列は、変数の時と同じように宣言と同時に値を代入(初期化)することができます。

#include <stdio.h>

int main()
{
    int arr[3] = { 10, 20, 30 };

    printf("arr[0]: %d\narr[1]: %d\narr[2]: %d",
        arr[0], arr[1], arr[2]);

    getchar();
}
arr[0]: 10
arr[1]: 20
arr[2]: 30

要素数3の配列を宣言すると同時に、先頭から順に10、20、30の値で初期化しています。
配列の宣言に続き、波括弧で配列に代入したい値を記述します。
これを初期化子といいます。

この書き方ができるのは配列の宣言時のみです。
配列を宣言した後に値を代入する場合にはこの方法は使えません。

int arr[3];

//これはダメ
arr = { 10, 20, 30 };

//これもダメ
arr[3] = { 10, 20, 30 };

要素数を指定しないで初期化

配列の宣言と初期化を同時に行う場合は、要素数の指定を省略することもできます。

#include <stdio.h>

int main()
{
    int arr[] = { 10, 20, 30 };

    printf("arr[0]: %d\narr[1]: %d\narr[2]: %d",
        arr[0], arr[1], arr[2]);

    getchar();
}

このコードでは、初期化子の値の数から自動的に要素数3の配列を作成してくれます。

要素数を省略し、かつ初期化子も指定しない宣言はエラーになります。
配列の宣言時に要素数が確定できる必要があります。

//これはダメ
int arr[];

初期化子が要素数より少ない場合

配列の宣言と初期化を同時に行う場合、指定した要素数よりも少ない数の初期化子で初期化することができます。
この時、残った要素は0で初期化されます。

#include <stdio.h>

int main()
{
    int arr[3] = { 10, 20 };

    printf("arr[0]: %d\narr[1]: %d\narr[2]: %d",
        arr[0], arr[1], arr[2]);

    getchar();
}
arr[0]: 10
arr[1]: 20
arr[2]: 0

要素数3の配列に対して、初期化子はふたつしかありません。
この場合、先頭から値を埋めていき、余ったarr[2]は0で初期化されます。

これを利用すると、要素数が100だろうが1000だろうがすべてゼロで初期化してしまうことができます。

int arr[100] = {};

このように書くと、配列arrの100個の要素すべてに0が代入された状態になります。

0で初期化したい場合は、必ず初期化子と共に配列を宣言してください。
初期化子なしで配列を宣言した場合、要素に値を代入するまではその要素は使えません。

int arr[100];

//初期化されていないのでエラー
printf("%d", arr[0])

以下のコードのように書いても1で初期化されるのは先頭要素のみで、後はすべて0で初期化されることに注意してください。

//先頭要素のみ1で初期化、
//後はすべて0で初期化
int arr[100] = { 1 };

配列でできないこと

配列の要素数の変更

C言語では、一度宣言した配列の要素数を変更することはできません。
(他の言語ではできるものもあります)

配列のサイズを変更したい場合は、新しい配列を作って元の配列の値をコピーする方法があります。

配列の要素数指定に変数を使用

配列のサイズの指定に変数を指定することはできません。

int kazu = 5;

//変数で配列の要素数を決定できない
//これはエラー
int arr1[kazu];

//確定した「数値」を指定しなければならない
//これはOK
int arr2[5];

配列の要素数に指定できるのは「定数」という、値が変わらないものに限られます。
変数のように、何が入っているかわからない値では配列の要素数を決定することはできません。
上のようなサンプルコードでは変数kazuの値は「5」であることは(人間にとっては)明らかなのですが、それでもできません。

コンパイラによっては可変長配列という機能がサポートされている場合があり、この書き方が許可されている場合があります。
(Visual Studioではできない)

定数同士の計算はコンパイル時に値が決定されますので、要素数に指定することができます。

//OK
int arrKazu1[10 / 2];

配列の要素数を計算で得る

配列の要素数は以下のような計算で算出することができます。

#include <stdio.h>

int main(void)
{
	int arr[] = { 0, 1, 2, 3, 4, 5 };

	int length = sizeof(arr) / sizeof(arr[0]);

	printf("配列arrの要素数: %d", length);

	getchar();
}
配列arrの要素数: 6

sizeofというのは演算子の一種で、指定したデータのサイズ(バイト数)を得ることができます。
これに配列を指定すると、その配列全体のサイズを得ることができます。

sizeof演算子に配列の先頭の要素を指定すると、要素ひとつ分のサイズを得ることができます。
配列全体のサイズを配列要素ひとつ分のサイズで割ると、配列の要素数が得られるというわけです。
(上記コードは「24 / 4 = 6」の計算となります)