
C言語の基本|配列とfor文
配列の番号をfor文でたどれば、たくさんのデータも短いコードでまとめて扱える。
配列を使うと、同じ型のデータをひとまとまりにして保存できます。しかし、配列の要素を1つずつ個別に入力したり表示したりしていては、要素が増えるほどコードも長くなってしまいます。
そこで組み合わせたいのがfor文です。
for文の変数を配列の添字として使えば、先頭の要素から最後の要素まで順番に処理できます。入力、表示、合計など、配列を使う多くの処理は、この組み合わせを基本にして作られます。
この記事では、インデックス変数と添字の関係、入力と表示の方法、範囲外アクセスを防ぐ条件式、要素数をマクロで管理する方法を順番に解説します。
配列にfor文を組み合わせる理由
配列は、同じ型の値を複数保存するための仕組みです。たとえば、5日分の運動時間を保存するなら、次のように宣言できます。
int minutes[5];この配列には、次の5つの要素があります。
| 要素の順番 | 添字 | 要素の指定 |
|---|---|---|
| 1番目 | 0 | minutes[0] |
| 2番目 | 1 | minutes[1] |
| 3番目 | 2 | minutes[2] |
| 4番目 | 3 | minutes[3] |
| 5番目 | 4 | minutes[4] |
配列の各要素に対して同じ処理を行うとき、個別にコードを書く方法では手間がかかります。
printf("%d\n", minutes[0]);
printf("%d\n", minutes[1]);
printf("%d\n", minutes[2]);
printf("%d\n", minutes[3]);
printf("%d\n", minutes[4]);for文を使えば、同じ処理を次のようにまとめられます。
for (int i = 0; i < 5; i++) {
printf("%d\n", minutes[i]);
}処理する要素が5個から10個に増えても、printfを何行も追加する必要はありません。繰り返す回数を変更するだけで対応できます。
図1:for文が配列を順番にたどる仕組み

この図から分かること
for文の変数iは、配列の添字としてそのまま利用できます。
iが0ならminutes[0]、iが1ならminutes[1]というように、iを1ずつ増やすことで全要素を順番に処理できます。配列が5要素なら、添字の範囲は0から4までです。
インデックス変数と添字の関係
配列を処理するfor文では、iのように現在位置を表す変数をよく使います。この変数は、インデックス変数と呼ばれます。
for (int i = 0; i < 5; i++) {
printf("%d\n", minutes[i]);
}このfor文では、次の順序で処理が進みます。
| 繰り返し | iの値 | 処理する要素 |
|---|---|---|
| 1回目 | 0 | minutes[0] |
| 2回目 | 1 | minutes[1] |
| 3回目 | 2 | minutes[2] |
| 4回目 | 3 | minutes[3] |
| 5回目 | 4 | minutes[4] |
基本形は次のとおりです。
for (int i = 0; i < 要素数; i++) {
配列名[i]を使った処理;
}各部分には、次の役割があります。
| 記述 | 役割 |
|---|---|
| int i = 0 | 先頭要素の添字0から始める |
| i < 要素数 | 配列の範囲内にいる間だけ続ける |
| i++ | 次の要素へ進む |
| 配列名[i] | 現在の要素を指定する |
要素数が5の場合、条件をi < 5とすれば、iの値は0、1、2、3、4となります。これで5個すべてを、範囲内で安全に処理できます。
配列の全要素へ順番に入力する
配列へ入力するときも、インデックス変数を添字として使います。
for (int i = 0; i < 5; i++) {
scanf("%d", &minutes[i]);
}scanfには、入力値の保存先となるアドレスを渡します。そのため、配列の要素minutes[i]の前にも&が必要です。
int value;
scanf("%d", &value);普通の変数へ入力するときに&valueと書くのと同じ考え方です。配列の各要素も、1つずつ見ればint型の変数として扱えます。
表示用の番号と配列の添字は分けて考える
C言語の配列は添字0から始まりますが、利用者へ見せる番号は1から始めたほうが自然な場合があります。
printf("%d日目の運動時間を入力してください > ", i + 1);このとき、入力先はminutes[i]です。
| i | 画面に表示する番号 | 入力先 |
|---|---|---|
| 0 | 1日目 | minutes[0] |
| 1 | 2日目 | minutes[1] |
| 2 | 3日目 | minutes[2] |
| 3 | 4日目 | minutes[3] |
| 4 | 5日目 | minutes[4] |
iは配列内部の位置を指定し、i + 1は人に見せる番号として使います。この2つを混同しないことが大切です。
5日分の運動時間を入力して表示するプログラム
ファイル名:10_4_1.c
#include <stdio.h>
int main(void)
{
int minutes[5];
/* 5日分の運動時間を入力する */
for (int i = 0; i < 5; i++) {
printf("%d日目の運動時間を入力してください(分)> ", i + 1);
scanf("%d", &minutes[i]);
}
/* 入力された運動時間を順番に表示する */
printf("\n入力された運動時間\n");
for (int i = 0; i < 5; i++) {
printf("%d日目:%d分\n", i + 1, minutes[i]);
}
return 0;
}実行結果の例
1日目の運動時間を入力してください(分)> 30
2日目の運動時間を入力してください(分)> 45
3日目の運動時間を入力してください(分)> 20
4日目の運動時間を入力してください(分)> 60
5日目の運動時間を入力してください(分)> 35
入力された運動時間
1日目:30分
2日目:45分
3日目:20分
4日目:60分
5日目:35分プログラムの詳しい解説
最初に、5個の整数を保存できる配列minutesを宣言しています。
int minutes[5];この配列の有効な添字は0から4までです。宣言した直後の要素は不定値なので、最初のfor文ですべての要素へ値を入力しています。
for (int i = 0; i < 5; i++) {
printf("%d日目の運動時間を入力してください(分)> ", i + 1);
scanf("%d", &minutes[i]);
}iは0から始まり、1回繰り返すたびにi++で1増えます。iが5になるとi < 5が偽になるため、ループは終了します。
2つ目のfor文では、入力済みの値を同じ順番で表示しています。
for (int i = 0; i < 5; i++) {
printf("%d日目:%d分\n", i + 1, minutes[i]);
}入力と表示で同じ添字の進み方を使っているため、1日目に入力した値は1日目として正しく表示されます。
図2:入力用ループと表示用ループの役割

この図から分かること
入力用のfor文は配列へ値を保存し、表示用のfor文は保存済みの値を取り出します。
処理内容は異なりますが、どちらもiを0から4まで変化させて同じ配列を順番にたどっています。配列全体を処理するときは、このように目的ごとにfor文を分けると流れが分かりやすくなります。
for文の条件はi < 要素数にする
要素数5の配列を処理するときは、次の条件が基本です。
for (int i = 0; i < 5; i++)iの変化を確認すると、最後に処理されるのはiが4のときです。
0 → 1 → 2 → 3 → 4 → 終了次のようにi <= 5と書いてはいけません。
for (int i = 0; i <= 5; i++) {
printf("%d\n", minutes[i]);
}この条件では、iが5のときもループ本体が実行されます。その結果、存在しないminutes[5]へアクセスしてしまいます。
| 配列の要素数 | 正しい添字 | 正しい条件 |
|---|---|---|
| 3 | 0~2 | i < 3 |
| 5 | 0~4 | i < 5 |
| 10 | 0~9 | i < 10 |
要素数がNなら、最後の添字はN - 1です。そのため、条件をi < Nと書けば配列の範囲内だけを処理できます。
範囲外アクセスが危険な理由
次の配列で利用できるのはminutes[0]からminutes[4]までです。
int minutes[5];以下のアクセスは範囲外です。
minutes[5]
minutes[8]
minutes[-1]C言語は、添字が範囲内かどうかを自動では確認してくれません。範囲外の場所へ読み書きすると、別のデータを書き換えたり、不定な値を読み出したりする可能性があります。
配列をfor文で扱うときは、次の点を確認しましょう。
- インデックス変数を0から始めているか
- 条件がi < 要素数になっているか
- 配列の要素数とループ回数が一致しているか
- 負の添字になる処理がないか
配列の要素数をマクロで管理する
要素数をコードの複数箇所へ直接書くと、変更するときに修正漏れが起こりやすくなります。
int temperatures[5];
for (int i = 0; i < 5; i++) {
/* 処理 */
}この5に意味のある名前を付けると、管理しやすくなります。
#define MEASURE_COUNT 5配列の宣言とfor文の条件で、同じマクロを使用できます。
int temperatures[MEASURE_COUNT];
for (int i = 0; i < MEASURE_COUNT; i++) {
/* 処理 */
}測定回数を変更するときは、マクロ定義の1か所を修正するだけです。
気温を入力して合計を求めるプログラム
ファイル名:10_4_2.c
#include <stdio.h>
#define MEASURE_COUNT 5
int main(void)
{
int temperatures[MEASURE_COUNT];
int total = 0;
/* 各回の気温を入力する */
for (int i = 0; i < MEASURE_COUNT; i++) {
printf("%d回目の気温を入力してください(℃)> ", i + 1);
scanf("%d", &temperatures[i]);
}
/* 全要素を表示しながら合計する */
printf("\n入力された気温\n");
for (int i = 0; i < MEASURE_COUNT; i++) {
printf("%d回目:%d℃\n", i + 1, temperatures[i]);
total += temperatures[i];
}
printf("気温の合計は%dです。\n", total);
return 0;
}実行結果の例
1回目の気温を入力してください(℃)> 18
2回目の気温を入力してください(℃)> 21
3回目の気温を入力してください(℃)> 20
4回目の気温を入力してください(℃)> 23
5回目の気温を入力してください(℃)> 19
入力された気温
1回目:18℃
2回目:21℃
3回目:20℃
4回目:23℃
5回目:19℃
気温の合計は101です。プログラムの詳しい解説
MEASURE_COUNTは、配列に保存する気温の個数を表しています。
#define MEASURE_COUNT 5マクロ定義の行にはセミコロンを付けません。プログラム中のMEASURE_COUNTは、前処理によって5へ置き換えられます。
配列の要素数にもMEASURE_COUNTを使用しています。
int temperatures[MEASURE_COUNT];入力用と計算用のfor文にも同じマクロを使っているため、配列の要素数とループ回数を合わせやすくなっています。
for (int i = 0; i < MEASURE_COUNT; i++)合計を保存するtotalは、ループを始める前に0で初期化しています。
int total = 0;各要素を順番に加算する処理は次の部分です。
total += temperatures[i];これは、現在のtotalにtemperatures[i]の値を加え、結果を再びtotalへ代入しています。iが0から4まで変化するため、配列の全要素が1回ずつ合計されます。
for文で配列を処理する定番の形
配列とfor文には、よく使われる組み合わせがあります。
全要素へ入力する
for (int i = 0; i < 要素数; i++) {
scanf("%d", &array[i]);
}全要素を表示する
for (int i = 0; i < 要素数; i++) {
printf("%d\n", array[i]);
}全要素を合計する
int sum = 0;
for (int i = 0; i < 要素数; i++) {
sum += array[i];
}どの処理でも、配列をたどる部分は共通です。変わるのは、ループ本体で配列要素に対して何をするかです。
図3:配列処理を組み立てる3つの視点

この図から分かること
配列をfor文で処理するときは、最初に要素数を確認し、次に添字の範囲を決めます。そのうえで、入力、表示、合計などの処理をループ本体へ書きます。
要素数が5なら、添字は0から4です。この関係を保つi < 要素数という条件が、安全な配列処理の基本になります。
配列とfor文でつまずきやすいポイント
| つまずきやすい書き方 | 問題点 | 見直し方 |
|---|---|---|
| iを1から始める | 先頭の要素を処理できないことがある | 基本はi = 0から始める |
| i <= 要素数と書く | 最後に範囲外へアクセスする | i < 要素数にする |
| scanfで&を付けない | 入力値の保存先を正しく渡せない | &array[i]と書く |
| 表示番号にもiを使う | 0日目や0人目と表示される | 表示にはi + 1を使う |
| 要素数を何度も直書きする | 変更漏れが起こりやすい | 意味のあるマクロ名で管理する |
| 入力前の要素を表示する | 不定値を使う可能性がある | 値を入れてから参照する |
配列の添字と、人に見せる番号は同じとは限りません。内部では0から数え、表示では必要に応じて1を加える。この区別ができると、配列とfor文のコードを安定して書けるようになります。
