C言語のきほん|for文で配列を処理する

配列は、for文と組み合わせるともっと便利。繰り返し処理を覚えると、たくさんのデータをすっきり扱えるようになります

配列を学び始めると、次に自然と出てくるのが「配列の要素をまとめて処理したい」という場面です。
1つ1つの要素に対して個別に代入したり表示したりすることもできますが、要素数が増えてくると、同じようなコードを何度も書くことになってしまいます。

たとえば、5人分の点数、7日分の売上、12か月分の気温のように、同じ型のデータがたくさんある場合、それを1つずつ手で書くのはとても大変です。
しかも、あとから要素数が変わると、修正する場所も増えてしまいます。

そんなときに活躍するのが for文 です。
for文を使うと、配列の先頭から末尾までを順番に処理できます。
入力、表示、合計、検索など、配列に対する基本的な操作の多くは、for文と組み合わせることでとても自然に書けるようになります。

ここでは、for文を使って配列を処理する基本を、やさしく丁寧に見ていきます。
インデックス変数の役割、添字との関係、入力と表示の流れ、範囲外アクセスへの注意、さらに要素数をマクロで管理する書き方まで、順番に整理していきましょう。

なぜ配列にfor文を使うのか

配列は、同じ型のデータを複数まとめて扱う仕組みです。
そして、配列の各要素に対して同じ処理を順番に行いたいことがとても多いです。

たとえば、次のような処理です。

やりたいこと配列全体に対する処理
値を入力する全要素に順番に値を入れる
値を表示する全要素を順番に表示する
合計する全要素を順番に足す
条件を調べる全要素を順番に確認する

こうした処理を1個ずつ手で書くと、コードが長くなります。
でも、for文を使えば、同じ処理を繰り返し書かずにすみます。

配列とfor文はとても相性がよい

配列の添字は 0 から始まります。
たとえば要素数 5 の配列なら、使える添字は 0、1、2、3、4 です。

for文も、次のように 0 から始めて 1 ずつ増やしていく書き方が得意です。

for (int i = 0; i < 5; i++) {
    /* 処理 */
}

この i が、配列の添字としてそのまま使えます。
つまり、for文のカウンタ変数と配列の添字は非常に相性がよいのです。

インデックス変数とは

配列をfor文で処理するときに使う i のような変数は、インデックス変数 と呼ばれることがあります。
これは、配列のどの位置を処理しているかを表すための変数です。

たとえば次のように使います。

scores[i]

この式では、i の値によってアクセスする要素が変わります。

i の値アクセスする要素
0scores[0]
1scores[1]
2scores[2]
3scores[3]
4scores[4]

このように、i を変化させることで、配列の各要素を順番に処理できます。

for文で配列を処理する基本形

配列を順番に処理する基本の形は次のようになります。

for (int i = 0; i < 要素数; i++) {
    配列名[i] を使った処理;
}

この形を覚えておくと、とても便利です。
配列の先頭から末尾までを1回ずつ順番にたどる、という意味になります。

このfor文の意味

部分意味
int i = 0添字を0から始める
i < 要素数配列の範囲内だけ繰り返す
i++添字を1つずつ進める

ここで特に大切なのは、条件式を i < 要素数 にすることです。
要素数が5なら、i は 0 から 4 までになります。
これが配列の範囲内アクセスにつながります。

サンプルプログラムで見てみよう

5日分の歩数を配列に入力し、そのあと全て表示するシンプルなプログラム例です。
コメントもメッセージも日本語にしています。

サンプルプログラム

ファイル名:10_4_1.c

#include <stdio.h>

int main(void)
{
    int steps[5];   // 5日分の歩数を保存する配列

    // 配列に値を入力する
    for (int i = 0; i < 5; i++) {
        printf("%d日目の歩数を入力してください> ", i + 1);
        scanf("%d", &steps[i]);
    }

    // 配列の値を表示する
    printf("\n入力された歩数:\n");
    for (int i = 0; i < 5; i++) {
        printf("%d日目の歩数: %d\n", i + 1, steps[i]);
    }

    return 0;
}

実行結果の例

1日目の歩数を入力してください> 5200
2日目の歩数を入力してください> 6100
3日目の歩数を入力してください> 4800
4日目の歩数を入力してください> 7000
5日目の歩数を入力してください> 5600

入力された歩数:
1日目の歩数: 5200
2日目の歩数: 6100
3日目の歩数: 4800
4日目の歩数: 7000
5日目の歩数: 5600

このプログラムの入力部分を見てみよう

まずは入力部分です。

for (int i = 0; i < 5; i++) {
    printf("%d日目の歩数を入力してください> ", i + 1);
    scanf("%d", &steps[i]);
}

このfor文では、i が 0 から 4 まで変化します。
そのたびに、steps[i] を使って配列の各要素に値を入力しています。

入力時の対応関係

i の値表示される日数入力される要素
01日目steps[0]
12日目steps[1]
23日目steps[2]
34日目steps[3]
45日目steps[4]

ここで、表示では i + 1 を使っている点にも注目です。
配列の添字は 0 から始まりますが、人に見せる日数や人数は 1 から表示したほうが自然です。
そのため、表示用には i + 1 を使っています。

scanf でなぜ &steps[i] を使うのか

入力部分では、次のように書いています。

scanf("%d", &steps[i]);

scanf は、入力された値をどこに保存するかを指定する必要があります。
そのため、steps[i] の アドレス を渡すために & をつけています。

これは普通の変数のときと同じ考え方です。

int x;
scanf("%d", &x);

配列の要素も、1つ取り出せば普通の変数のように扱えます。
だから、steps[i] に入力したいときは &steps[i] と書きます。

このプログラムの表示部分を見てみよう

次は表示部分です。

for (int i = 0; i < 5; i++) {
    printf("%d日目の歩数: %d\n", i + 1, steps[i]);
}

ここでも i は 0 から 4 まで変化します。
そのたびに steps[i] を取り出して表示しています。

つまり、入力も表示も、
for文で i を順番に変化させながら、配列の各要素を処理している
というわけです。

for文を使わない場合と比べてみよう

もし for文 を使わずに同じ処理を書こうとすると、次のようになります。

printf("1日目の歩数を入力してください> ");
scanf("%d", &steps[0]);

printf("2日目の歩数を入力してください> ");
scanf("%d", &steps[1]);

printf("3日目の歩数を入力してください> ");
scanf("%d", &steps[2]);

printf("4日目の歩数を入力してください> ");
scanf("%d", &steps[3]);

printf("5日目の歩数を入力してください> ");
scanf("%d", &steps[4]);

これでは、同じようなコードを何度も書くことになります。
表示部分も同じように長くなります。

for文を使えば、この繰り返しを短く、分かりやすく書けます。
これが、配列処理で for文 が一般的に使われる大きな理由です。

添字は0から始まることに注意しよう

配列をfor文で処理するとき、最も大切な注意点の1つが、添字は 0 から始まることです。

要素数が5なら、使える添字は次の通りです。

要素添字
1個目0
2個目1
3個目2
4個目3
5個目4

そのため、for文の条件は通常次のように書きます。

for (int i = 0; i < 5; i++)

もしこれを次のように書いてしまうと問題です。

for (int i = 0; i <= 5; i++)

この場合、i が 5 のときまで処理してしまうので、steps[5] にアクセスする可能性があります。
でも、要素数5の配列で使える最後の添字は 4 です。
つまり steps[5] は範囲外です。

範囲外アクセスはとても危険

配列の範囲外にアクセスすると、予期しない動作やバグ、場合によってはプログラムの異常終了につながることがあります。
これを 範囲外アクセス と呼びます。

たとえば次のような配列があるとします。

int steps[5];

このとき正しい範囲は、

  • steps[0]
  • steps[1]
  • steps[2]
  • steps[3]
  • steps[4]

です。

次のような指定は危険です。

steps[5]
steps[6]
steps[-1]

C言語では、このような範囲外アクセスを自動で防いでくれません。
だからこそ、for文の条件式を正しく書くことがとても重要です。

配列の要素数をマクロで管理する方法

サンプルでは 5 を直接書いていましたが、実際には要素数をマクロで管理することがよくあります。
これをすると、あとから要素数を変更しやすくなります。

マクロを使った例

#include <stdio.h>
#define DAY_COUNT 5

int main(void)
{
    int steps[DAY_COUNT];   // 配列の宣言

    // 配列に値を入力する
    for (int i = 0; i < DAY_COUNT; i++) {
        printf("%d日目の歩数を入力してください> ", i + 1);
        scanf("%d", &steps[i]);
    }

    // 配列の値を表示する
    printf("\n入力された歩数:\n");
    for (int i = 0; i < DAY_COUNT; i++) {
        printf("%d日目の歩数: %d\n", i + 1, steps[i]);
    }

    return 0;
}

マクロを使うメリット

要素数をマクロにしておくと、次のような利点があります。

メリット内容
修正が楽になる要素数を変える場所が1か所で済む
書き間違いを減らせる5 を何度も書かなくてよい
意図が伝わりやすいDAY_COUNT のような名前で意味が分かる

たとえば、あとから5日分ではなく7日分に変えたくなったとき、次の1か所を直すだけで済みます。

#define DAY_COUNT 7

もし数字の 5 をコードのあちこちに直接書いていたら、全部探して直さなければなりません。
そのため、要素数のような意味のある値はマクロで定義しておくと便利です。

インデックス変数と添字の関係を図で考えよう

for文で配列を処理するときの流れを図にすると、こうなります。

i = 0 → 配列[0] を処理
i = 1 → 配列[1] を処理
i = 2 → 配列[2] を処理
i = 3 → 配列[3] を処理
i = 4 → 配列[4] を処理

このように、インデックス変数 i がそのまま配列の添字として働きます。
だから、for文の開始値、条件、増やし方を正しく書くことが、配列処理の基本になります。

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];
}

このように、for文と配列を組み合わせると、いろいろな処理に発展させやすくなります。

よくあるつまずき

for文で配列を処理するときに、初心者がつまずきやすい点を整理しておきます。

つまずきやすい点内容
添字を1から始めてしまうC言語の配列は0から始まる
条件を i <= 5 にしてしまう要素数5なら最後は i < 5
scanf で & を忘れる入力先のアドレスが必要
表示の番号と添字を混同する表示は i + 1、添字は i
要素数を直接何度も書くマクロでまとめると管理しやすい

このあたりを意識すると、配列とfor文の組み合わせがかなり読みやすくなります。

なぜマクロ名を意味のある名前にするのか

マクロを使うときは、ただ数字を置き換えるだけでなく、意味のある名前にすることが大切です。

たとえば次の2つを比べてみてください。

#define N 5
#define DAY_COUNT 5

どちらも動作は同じですが、DAY_COUNT のほうが「日数の数」であることが伝わりやすいです。
こうした名前づけをすると、コードを読んだときに意図が分かりやすくなります。

for文で配列を処理する考え方を整理しよう

ここまでの内容をまとめると、配列をfor文で処理するときは、次の流れで考えると分かりやすいです。

視点内容
配列の要素数はいくつか何回繰り返すかを決める
添字の範囲はどこまでか0 から 要素数 - 1 まで
i は何を表すか配列のどの要素を処理しているか
入力か表示か計算か配列要素に対する処理内容を決める

この4つを確認しながらコードを見ると、配列処理の意味がかなりつかみやすくなります。

今後の学習につながる大切な基本

for文で配列を処理する考え方は、配列学習の中でもとても重要です。
この基本が分かると、合計値の計算、最大値の探索、平均値の計算、条件に合う要素の検索など、いろいろな処理へ広げられます。

配列だけでも便利ですが、for文と組み合わせることで、その便利さが一気に大きくなります。
配列の各要素を順番にたどる、という感覚がつかめるようになると、C言語で複数データを扱う力がぐっと伸びていきます。