C言語の基本|1次元配列の基本操作

宣言して、値を入れて、必要な要素を取り出す。1次元配列の基本操作を覚えて、複数のデータをすっきり管理しよう。

1次元配列の基本操作

C言語では、同じ型のデータを複数まとめて扱いたい場面がよくあります。

たとえば、次のようなデータです。

  • 5人分の点数
  • 7日分の売上
  • 10個の商品価格
  • 複数地点の測定値

配列を使わずに保存する場合は、データの数だけ変数を用意しなければなりません。

int value1;
int value2;
int value3;
int value4;
int value5;

この書き方でも値は保存できますが、変数が増えるほど管理しにくくなります。同じ処理を繰り返したい場合も、それぞれの変数名を個別に指定しなければなりません。

そこで役立つのが1次元配列です。

int values[5];

この1行で、int型の値を5個保存するための領域をまとめて用意できます。それぞれの要素には添字という番号が付いているため、必要な場所を指定して値を代入したり参照したりできます。

1次元配列の基本操作は、大きく分けると次の3つです。

  • 配列を宣言する
  • 要素に値を代入する
  • 要素を参照する

この3つの操作と、添字が0から始まるルールを理解すれば、配列の基本的なコードを読み書きできるようになります。

1次元配列とは

1次元配列は、同じ型のデータを一列に並べて保存する仕組みです。

番号の付いた箱が横一列に並び、それぞれの箱に値を保存するイメージを持つと分かりやすいでしょう。

配列を構成する一つひとつの保存場所を要素と呼びます。また、要素の位置を表す番号を添字と呼びます。

C言語では、添字は0から始まります。

たとえば、int型の要素を5個持つ配列は、次のように宣言します。

int values[5];

この配列には、次の5つの要素があります。

values[0]
values[1]
values[2]
values[3]
values[4]

1番目の要素はvalues[0]です。values[1]は2番目の要素を表します。

図1:1次元配列を構成する5つの要素

この図から分かること

配列valuesには、int型の要素が5個あります。

要素の位置と添字の対応は次のとおりです。

要素の位置添字要素の指定
1番目0values[0]
2番目1values[1]
3番目2values[2]
4番目3values[3]
5番目4values[4]

要素数は5ですが、最後の添字は4です。要素数と最後の添字を混同しないようにしましょう。

1次元配列を宣言する

1次元配列を使うには、最初に配列を宣言します。

基本的な文法は次のとおりです。

型名 配列名[要素数];

各部分には、次の意味があります。

項目内容
型名各要素に保存するデータの型
配列名配列に付ける名前
要素数配列が持つ要素の個数

整数を5個保存する配列scoresなら、次のように宣言します。

int scores[5];

この宣言によって、int型の値を5個保存できる配列scoresが用意されます。

ほかの型でも、同じ形で宣言できます。

宣言内容
int scores[5];int型の要素を5個持つ
double prices[8];double型の要素を8個持つ
char letters[10];char型の要素を10個持つ

1つの配列に保存する要素は、すべて同じ型です。int型の配列へはint型の値、double型の配列へはdouble型の値を保存します。

宣言しただけでは要素の値は決まらない

関数内で次のように配列を宣言しただけでは、各要素の値は初期化されていません。

int scores[5];

この時点の状態は、次のように考えられます。

要素状態
scores[0]不定値
scores[1]不定値
scores[2]不定値
scores[3]不定値
scores[4]不定値

不定値とは、使用できる値が設定されていない状態です。不定値の要素を参照してはいけません。

安全に使うためには、値を参照する前に次のどちらかを行います。

  • 各要素へ値を代入する
  • 宣言と同時に配列を初期化する

宣言したことと、値を設定したことは別の操作です。

要素数と添字の違い

配列を扱うときは、要素数と添字を区別する必要があります。

int scores[5];

この配列の要素数は5ですが、使用できる添字は0から4です。

項目
要素数5
最初の添字0
最後の添字4

一般的には、要素数がnなら使用できる添字は0からn - 1です。

要素数使用できる添字
10
30~2
50~4
100~9

要素数5の配列でscores[5]を指定すると、6番目の要素を使おうとすることになります。これは配列の範囲外です。

1次元配列の要素に値を代入する

宣言した配列には、添字を使って要素ごとに値を代入します。

基本的な形は次のとおりです。

配列名[添字] = 値;

たとえば、配列scoresの先頭から3つの要素へ値を代入する場合は、次のように書きます。

scores[0] = 85;
scores[1] = 92;
scores[2] = 78;

それぞれの文には、次の意味があります。

代入内容
scores[0] = 85;1番目の要素に85を代入する
scores[1] = 92;2番目の要素に92を代入する
scores[2] = 78;3番目の要素に78を代入する

配列全体ではなく、添字で指定した1つの要素へ値を入れています。

一部の要素だけに代入した場合

次のコードでは、5個ある要素のうち、先頭から3個だけに値を代入しています。

int scores[5];

scores[0] = 85;
scores[1] = 92;
scores[2] = 78;

代入後の状態は次のとおりです。

要素値または状態
scores[0]85
scores[1]92
scores[2]78
scores[3]不定値
scores[4]不定値

値を代入した要素だけが使用できる状態になります。scores[3]とscores[4]には値を設定していないため、まだ参照してはいけません。

配列を宣言したからといって、すべての要素へ同じ値が自動的に入るわけではありません。

図2:代入済みの要素と不定値の要素

この図から分かること

配列の一部へ値を代入しても、ほかの要素まで自動的に初期化されるわけではありません。

図では、levels[0]からlevels[2]までに値が入っています。一方、levels[3]とlevels[4]には値を代入していないため、不定値のままです。

配列を安全に使うには、どの要素に値を設定したかを把握しておく必要があります。

1次元配列の要素を参照する

配列に保存した値を取り出して使うことを、要素の参照といいます。

要素を参照するときも、配列名と添字を使います。

配列名[添字]

たとえば、scores[0]に保存されている値を表示するなら、次のように書きます。

printf("%d\n", scores[0]);

複数の要素を順番に表示する場合は、次のように記述できます。

printf("%d\n", scores[0]);
printf("%d\n", scores[1]);
printf("%d\n", scores[2]);

scores[0]、scores[1]、scores[2]は、それぞれ1つのint型の値として扱われます。

配列要素は普通の変数のように使える

添字で指定した配列要素は、普通の変数と同じように計算や代入に使えます。

たとえば、2つの要素を加算できます。

int total;

total = scores[0] + scores[1];

scores[0]が85、scores[1]が92なら、totalには177が代入されます。

要素の値を変更することもできます。

scores[0] = scores[0] + 5;

この処理では、scores[0]の値に5を加え、その結果を同じ要素へ代入します。

複合代入演算子を使えば、次のようにも書けます。

scores[0] += 5;

配列全体は複数の値のまとまりですが、添字を付けた1つの要素は、普通の変数のように扱えます。

1次元配列の基本操作をプログラムで確認する

ここでは、5地点分の騒音レベルを保存する配列を使います。

配列には5個の要素がありますが、今回は先頭から3個だけに値を代入し、その3個だけを参照します。

3地点分の騒音レベルを配列へ代入して表示するプログラム

ファイル名:10_2_1.c

#include <stdio.h>

int main(void)
{
    /* 5地点分の騒音レベルを保存する配列を宣言する */
    int levels[5];

    /* 先頭から3つの要素に値を代入する */
    levels[0] = 42;    /* 1地点目 */
    levels[1] = 48;    /* 2地点目 */
    levels[2] = 39;    /* 3地点目 */

    /* 値を代入した3つの要素を参照して表示する */
    printf("%d\n", levels[0]);
    printf("%d\n", levels[1]);
    printf("%d\n", levels[2]);

    return 0;
}
実行結果の例
42
48
39

配列の宣言を確認する

最初に、次の宣言によって配列levelsを用意しています。

int levels[5];

この配列には、int型の要素が5個あります。

levels[0]
levels[1]
levels[2]
levels[3]
levels[4]

宣言した直後は、各要素に使用できる値が設定されていません。そのため、値を代入する前にprintfで表示してはいけません。

要素への代入を確認する

次の部分では、先頭から3つの要素へ値を代入しています。

levels[0] = 42;
levels[1] = 48;
levels[2] = 39;

対応関係は次のとおりです。

地点要素騒音レベル
1地点目levels[0]42
2地点目levels[1]48
3地点目levels[2]39

1地点目をlevels[0]で表している点が重要です。C言語の添字は0から始まります。

要素の参照を確認する

値を表示する部分では、代入済みの要素だけを参照しています。

printf("%d\n", levels[0]);
printf("%d\n", levels[1]);
printf("%d\n", levels[2]);

levels[0]には42、levels[1]には48、levels[2]には39が入っているため、これらの値が順番に表示されます。

levels[3]とlevels[4]には値を代入していないので、このプログラムでは参照していません。

宣言・代入・参照の関係

プログラム内の操作を整理すると、次のようになります。

操作コード役割
宣言int levels[5];int型の要素を5個用意する
代入levels[0] = 42;1番目の要素へ42を入れる
参照printf("%d\n", levels[0]);1番目の要素を表示する

宣言は保存場所を用意する操作です。代入は指定した要素に値を入れる操作です。参照は保存されている値を取り出して使う操作です。

この3つは、それぞれ別の役割を持っています。

初期化との違い

配列には、宣言と同時に値を設定する初期化という書き方もあります。

int levels2[] = {42, 48, 39, 45, 41};

この場合は、配列を用意すると同時に、すべての要素へ値が入ります。

要素初期値
levels2[0]42
levels2[1]48
levels2[2]39
levels2[3]45
levels2[4]41

初期値が5個あるため、角括弧の中の要素数を省略しても、要素数は5になります。

宣言、代入、初期化の違いは次のとおりです。

操作内容
宣言int a[5];配列の保存場所を用意する
代入a[0] = 10;宣言後に1要素へ値を入れる
初期化int a[] = {10, 20, 30};宣言と同時に値を入れる

今回の中心は宣言、代入、参照ですが、初期化を使えば未設定の要素を減らしやすくなります。

一部だけ初期化した場合

要素数を指定し、初期値を一部だけ書くこともできます。

int data[5] = {10, 20};

この場合、残りの要素は0で初期化されます。

要素
data[0]10
data[1]20
data[2]0
data[3]0
data[4]0

配列全体を0で初期化する場合は、次のように書けます。

int data[5] = {0};

宣言だけを行う場合と、初期値を指定して宣言する場合では、要素の状態が異なる点を覚えておきましょう。

添字の範囲外へアクセスしてはいけない

配列では、使用できる添字の範囲を必ず守ります。

次の配列では、使用できる添字は0から4です。

int levels[5];

次の指定は範囲外です。

levels[5] = 50;
levels[-1] = 30;

levels[5]は6番目の要素を指定していますが、配列には5個しか要素がありません。levels[-1]は配列の先頭より前を指定しています。

C言語では、範囲外アクセスをしても、必ずその場で分かりやすいエラーが表示されるとは限りません。ほかのデータを壊したり、実行結果がおかしくなったりする可能性があります。

添字が正しい範囲にある条件は、次のように表せます。

0 <= 添字 && 添字 < 要素数

for文と組み合わせて参照する

配列の要素は、for文で添字を変化させながら順番に参照できます。

5個の要素をすべて初期化した配列なら、次のように表示できます。

int levels[] = {42, 48, 39, 45, 41};

for (int i = 0; i < 5; i++) {
    printf("%d\n", levels[i]);
}

iは0、1、2、3、4と変化します。そのため、次の要素が順番に参照されます。

levels[0]
levels[1]
levels[2]
levels[3]
levels[4]

for文の条件がi < 5になっている点が重要です。i <= 5にすると、範囲外のlevels[5]まで参照してしまいます。

図3:宣言・代入・参照の基本的な流れ

この図から分かること

1次元配列の基本操作は、宣言、代入、参照の順番で考えると分かりやすくなります。

  • 宣言で要素を保存する場所を用意する
  • 代入で指定した要素へ値を入れる
  • 参照で保存されている値を取り出して使う

宣言しただけの要素は、不定値のままです。値を代入または初期化してから参照する必要があります。

また、代入と参照のどちらでも添字を使います。添字が配列の範囲内にあることを確認しましょう。

普通の変数と1次元配列を比べる

普通の変数は1つの値を保存します。1次元配列は、同じ型の値を複数保存します。

項目普通の変数1次元配列
保存できる値1個複数個
宣言例int level;int levels[5];
値の指定levellevels[0]
向いている処理単独の値同じ種類の複数データ
繰り返し処理個別の変数名では扱いにくい添字を変えて順番に扱える

配列の各要素は普通の変数と同じように使えますが、どの要素を使うかを添字で指定する点が異なります。

よくある間違いを確認する

1次元配列の基本操作では、次のような間違いが起こりやすくなります。

間違い正しい考え方
添字を1から始める最初の添字は0
要素数5なら添字5まで使えると思う最後の添字は4
宣言しただけで値が0になると思う関数内で宣言しただけなら不定値
一部へ代入すれば全要素が使えると思う未代入の要素は参照しない
levels[5]へ代入する要素数5ならlevels[0]~levels[4]を使う
配列名だけで1要素を指定する配列名と添字で指定する
for文をi <= 要素数で回すi < 要素数で回す

特に、要素数と最後の添字の違いは重要です。

要素数が5なら、添字は次の5個です。

0、1、2、3、4

1次元配列を読むときの確認ポイント

1次元配列を含むプログラムでは、次の順番で確認すると処理を追いやすくなります。

  • 配列の型を確認する
  • 配列名を確認する
  • 要素数を確認する
  • 使用できる添字の範囲を確認する
  • どの要素に値を代入しているか確認する
  • 参照する要素に値が入っているか確認する
  • 添字が0から始まっているか確認する
  • 範囲外の要素を使用していないか確認する

1次元配列では、配列全体を一度に考えるよりも、添字で指定した1つの要素に注目すると理解しやすくなります。宣言で箱を用意し、代入で値を入れ、参照で取り出すという流れを意識して使いましょう。