C言語 配列の練習問題7問|添字・2次元配列まで固める
この記事は、C言語ドリルの4本目として配列を練習する記事です。複数のデータをひとつの変数にまとめるコードの書き方を身に着けます。
配列の宣言・添字から2次元配列までを7問の練習問題(基礎5問+発展2問)で手を動かして固めるドリルです。解答と解説は各問題の「+」を押すと開きます。まず自分で書いてみて、それから答え合わせをしてください。実務では、配列は「動作の履歴(ログ)を持つ」使い方が定番で、この記事でもそこまで踏み込みます。
<自己紹介>
筆者は現役の組込みエンジニアです。未経験向けのC言語練習問題を通じて最低限の言語知識を身につけ、最終的にはArduinoでマイコンプログラムを自作できるようになるのをゴールとして、このシリーズを作成しています。
目次
このテーマの要点
- 同じ型のデータをまとめて1つの名前で持つ(
int data[5];) - 1つずつは添字(index)で指す。先頭は0番
forと組み合わせて、全部を順に処理する
配列は前回のループとセットで使うことが多いです。「5教科の点数」「センサー値の履歴」「受信したデータの並び」など、数がまとまったデータは配列で扱います。
前提知識:配列の作り方・添字・2次元
① 作り方と初期化
変数の宣言との違いは、要素数(格納するデータの数)を決めることだけです。
int data[5] = {10, 20, 30, 40, 50};
// 5個の整数を1つの名前 data で持つ
data[0] = 99; // 読むだけでなく、書き換えもできる
② 添字(index)は0から始まる
data[0] // 先頭 → 10
data
// 2番目 → 20
data
// 最後(5個なら4番) → 50
0〜4 で、data[5] は存在しません。最大の添字は「宣言時の要素数 − 1」です。うっかり data[5] に触ると、他のデータを壊す危険なバグ(配列外アクセス)になります。
int data[5] のメモリ上の並び。名前は1つでも、中身は連続した5つの箱③ for で全部を順に処理する
for (int i = 0; i < 5; i++) {
printf("%d ", data[i]); // data[0]〜data
}
④ 2次元配列(表の形でデータを持つ)
ここまでの配列はデータが1列に並ぶ「1次元」でしたが、行×列の表の形でも持てます。それが2次元配列です。
int a
= {
{0, 1, 2, 3}, // 1行目
{4, 5, 6, 7} // 2行目
};
// a[行][列] で指す。a
は 6
イメージは表計算ソフトのセルです。a なら2行×4列=8個のデータが入ります。取り出すときは 

a[行][列] と添字を2つ書きます。ちなみに3次元(a)も作れて、xyz座標のようなデータで使われますが、4次元以降はほぼ使いません。まずは2次元まで知っていれば十分です。


より正確な仕様は、cppreference(C言語リファレンス)で確認できます。
例題(まずは一緒に解いてみる)
練習問題に入る前に、簡単な例題を1つ、答えを見ながら流れを確認しましょう。
例題:配列 {10, 20, 30} を作り、for で全部を順に表示してみましょう。
#include <stdio.h>
int main(void) {
int data
= {10, 20, 30};
for (int i = 0; i < 3; i++) {
printf("%d ", data[i]);
}
printf("\n");
return 0;
}
実行結果:10 20 30
解説:data[i] の i を 0→2 と動かして、全要素を取り出しています。添字は0からなので、3個の配列は data[0]〜data。条件を 
i < 3 にするのがポイントです。
流れはつかめましたか? ここからは、自分の手で解いてみましょう。
練習問題(基礎5+発展2)
基礎5問は必ず解いてください。発展2問は余力があればで大丈夫です。まず自分で書いてから、各問題の「+ 解答・解説を見る」を開いて答え合わせをしましょう。
基礎 Q1
5教科の成績(国語60・数学50・英語40・理科30・社会20)を1つの配列に格納し、国語:60 数学:50 英語:40 理科:30 社会:20 のように1行で表示してください。
解答・解説を見る
#include <stdio.h>
int main(void) {
int score[5] = {60, 50, 40, 30, 20};
printf("国語:%d 数学:%d 英語:%d 理科:%d 社会:%d\n",
score[0], score
, score
, score
, score
);
return 0;
}
実行結果:国語:60 数学:50 英語:40 理科:30 社会:20
解説:5教科ぶんの変数を5個作る代わりに、1つの配列にまとめて添字で取り出すのが配列の基本です。score[0] が国語、score が社会。教科が10個に増えても、配列の要素数を増やすだけで管理できます。「番号と中身の対応」を自分で決めるのがコツです。
基礎 Q2
Q1の成績 {60, 50, 40, 30, 20} の合計と平均を、for を使って求めて表示してください。
解答・解説を見る
#include <stdio.h>
int main(void) {
int score[5] = {60, 50, 40, 30, 20};
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += score[i];
}
printf("sum=%d avg=%d\n", sum, sum / 5);
return 0;
}
実行結果:sum=200 avg=40
解説:sum に1つずつ足していけば合計が出ます。Q1のように添字を5回書かずに、forで i を回すのが配列×ループの基本形です。平均は sum / 5。ここは整数どうしの割り算なので小数は切り捨てられます(今回は200÷5=40でちょうど割り切れます)。小数の平均がほしいときはキャストを思い出してください。
基礎 Q3
配列 {12, 45, 7, 33, 20} の中から、一番大きい値を探して表示してください。
解答・解説を見る
#include <stdio.h>
int main(void) {
int data[5] = {12, 45, 7, 33, 20};
int max = data[0]; // まず先頭を仮の最大に
for (int i = 1; i < 5; i++) {
if (data[i] > max) {
max = data[i]; // より大きければ更新
}
}
printf("max=%d\n", max);
return 0;
}
実行結果:max=45
解説:最大値探しの定石は「先頭を仮の最大とし、より大きいものが出たら入れ替える」です。i を1から回すのは、先頭を max の初期値にしたぶん、比較は2番目からで足りるからです。最小値なら不等号を < に変えるだけです。
基礎 Q4
配列 {10, 20, 30, 40, 50} を逆順(50から10へ)に表示してください。ヒント:for のカウンタは減らすこともできます。
解答・解説を見る
#include <stdio.h>
int main(void) {
int data[5] = {10, 20, 30, 40, 50};
for (int i = 4; i >= 0; i--) {
printf("%d ", data[i]);
}
printf("\n");
return 0;
}
実行結果:50 40 30 20 10
解説:「最後の添字(要素数−1=4)から始めて、0まで i-- で減らす」のが逆順の定石です。開始は i = 5 ではなく i = 4。ここを間違えると存在しない data[5] に触ってしまいます。「最大の添字は要素数−1」を体で覚える問題です。
基礎 Q5
次の表のデータを2次元配列に格納し、同じ2行×4列の形で表示してください。
| 0 | 1 | 2 | 3 |
| 4 | 5 | 6 | 7 |
解答・解説を見る
#include <stdio.h>
int main(void) {
int a
= {
{0, 1, 2, 3},
{4, 5, 6, 7}
};
for (int row = 0; row < 2; row++) {
for (int col = 0; col < 4; col++) {
printf("%d ", a[row][col]);
}
printf("\n"); // 1行ぶん表示したら改行
}
return 0;
}
実行結果:0 1 2 3 と 4 5 6 7 の2行
解説:2次元配列はforの二重ループとセットで使います。外側のforが「行」、内側のforが「列」を動かし、1行ぶん表示し終えたら改行する。この「二重ループで表をなめる」形は、画像処理やゲーム盤面など、あらゆる場面で再登場する基本パターンです。
発展 Q6
センサー値の記録 {512, 480, 1023, 505, 990} の中に、900以上の値(異常値とみなす)が何個あるかを数えて表示してください。ifとforと配列の総合問題です。
解答・解説を見る
#include <stdio.h>
int main(void) {
int data[5] = {512, 480, 1023, 505, 990};
int count = 0;
for (int i = 0; i < 5; i++) {
if (data[i] >= 900) {
count++; // 条件に合ったら数える
}
}
printf("count=%d\n", count);
return 0;
}
実行結果:count=2
解説:「配列をforでなめながら、ifで条件に合うものだけ数える」。この走査+条件カウントは、データ処理の頻出パターンです。1023と990の2個が900以上なので答えは2。しきい値を変えれば「エラーの回数」「規定値を超えた回数」など、いろいろな集計に応用できます。
発展 Q7
直近3件だけを記録する「ログ」を作ります。大きさ3の配列に、値 10, 20, 30, 40, 50 を順に入れていき、いっぱいになったら一番古いものから上書きしてください(リングバッファ)。最後に配列の中身を表示します。
解答・解説を見る
#include <stdio.h>
#define SIZE 3
int main(void) {
int log[SIZE] = {0};
int index = 0;
int inputs[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
log[index] = inputs[i]; // 今の位置に書く
index = (index + 1) % SIZE; // 次の位置へ(末尾なら先頭に戻る)
}
for (int i = 0; i < SIZE; i++) {
printf("%d ", log[i]);
}
printf("\n");
return 0;
}
実行結果:40 50 30
解説:カギは index = (index + 1) % SIZE です。% SIZE(3で割った余り)にすると、位置が 0→1→2→0→1… とぐるぐる回ります。だから4個目・5個目は、一番古い 10 と 20 の場所に上書きされ、最新3件だけが残ります(中身は最後に書いた位置の関係で 40 50 30 の並びになります)。大きさを増やさずに「直近N件」を持てるのがリングバッファの利点です。
この発展問題は余力がある人向けです。基礎5問ができていれば、次のテーマ(関数)に進んで大丈夫です。
例:実務で実際に書くコード
組込みで配列の出番が一番多いのが、「値の履歴を持つ」使い方です。センサー値は1回ごとにブレるので、直近の何個かを配列にためて平均すると、ノイズがならされて安定します。
int history[5]; // 直近5回ぶんの入れ物
// (メインループの中で)新しい値を入れて、平均を出す
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += history[i];
}
int average = sum / 5; // ノイズがならされた値
他にも、通信データも中身は配列でデータをやり取りすることが多く。CANやシリアル通信で受け取るデータは、バイト(数値)の並び=配列で定義されているため、ここでも配列を使ったりしますね。
そのため配列は実務でも頻繁にでてくるコードの書き方なので確実に理解しておいていただきたいです。
最後につまずきポイントをおさらい
0〜4 で、data[5] はありません。for の条件を i <= 5 と書くと、この配列外アクセスが起きます。i < 要素数 と覚えてください。PC上ではたまたま動くこともありますが、マイコンでは他のデータを壊す原因になります。もう一つは 初期化忘れです。int data[5]; と宣言しただけの配列には、何が入っているか分かりません(ゴミの値)。合計などに使う前に、{0} で初期化するか、値を入れてから使いましょう。
よくある質問(FAQ)
配列の要素数は後から変えられる?
基本のC言語の配列は、宣言した大きさのままです。組込みでは、この「固定の大きさ」がむしろ普通で、必要な最大数を最初に決めて確保します。だから「直近N件」のような使い方(リングバッファ)が定番になります。
要素数を数字で書かず、まとめて管理したい
#define SIZE 5 のように定数で決めておくと、int data[SIZE]; や for (i < SIZE) で使い回せて、後から数を変えるのも1か所で済みます。定数の使い方は#1 変数・型・演算子を参照してください。
文字列と配列は関係ある?
大ありです。C言語の文字列の正体はchar型の配列(文字の並び)です。配列に慣れておくと、文字列の扱いもすんなり理解できます。詳しくはポインタの記事で触れます。
次に読む
データをまとめて扱えるようになったら、次は「処理をまとめる」関数です。配列と関数を組み合わせると、コードが一気に整理できます。