
C言語基礎|配列の受渡しとconst
前回の「配列の受渡し」でつかんだ一番大事な感覚はこれでしたね。
関数が受け取った配列は、呼び出し側の配列そのものを参照しているように振る舞う
つまり、関数の中で配列要素を書き換えると、呼び出し側の配列も変わる可能性があります。
ここで多くの人が不安になります。
「えっ…関数に配列を渡すだけで、勝手に中身を書き換えられたら困るんだけど?」
その不安をスッと解消するために登場するのが const(型修飾子) です。
読み取り専用で使う関数には const を付ける—これがC言語の“安心設計”の基本ルールになります。

サンプルプログラム
ここでは 温度データを加工する関数と、温度データを表示する関数を作ります。
- 関数 adjust_all:配列の先頭 n 個の要素に、補正値を加える(書き換える)
- 関数 show_array:配列の先頭 n 個の要素を表示する(読むだけ=書き換えない)
サンプル:配列を書き換える関数と、読むだけの関数
プロジェクト名:chap6-15-1 ソースファイル名:chap6-15-1.c
Visual Studio でこのプログラムを実行するには、SDLチェック設定を変更しておく必要があります。
1.プロジェクト名を右クリックして、「プロパティ」をクリックします。
2.「C/C++」→「全般」→「SDLチェック」を「いいえ」に切り替えて「OK」をクリックします。
// 温度配列を補正し、表示する(constの有無を確認)
#include <stdio.h>
//--- 要素数nの配列vの先頭n個にoffsetを加える ---//
void adjust_all(int v[], int n, int offset)
{
for (int i = 0; i < n; i++)
v[i] += offset;
}
//--- 要素数nの配列vの先頭n個を表示して改行 ---//
void show_array(const int v[], int n)
{
printf("[ ");
for (int i = 0; i < n; i++)
printf("%d ", v[i]);
printf("]\n");
// もしここで v[0] = 999; などを書いたらコンパイルエラーになる(constだから)
}
int main(void)
{
int tokyo[] = {10, 12, 11, 9, 8};
int osaka[] = {14, 15, 13};
printf("補正前 Tokyo = "); show_array(tokyo, 5);
printf("補正前 Osaka = "); show_array(osaka, 3);
adjust_all(tokyo, 5, 2); // Tokyoの先頭5個を+2補正
adjust_all(osaka, 2, -1); // Osakaの先頭2個だけを-1補正(わざと一部だけ)
puts("補正後(配列の中身が更新されました)");
printf("補正後 Tokyo = "); show_array(tokyo, 5);
printf("補正後 Osaka = "); show_array(osaka, 3);
return 0;
}実行例
補正前 Tokyo = [ 10 12 11 9 8 ]
補正前 Osaka = [ 14 15 13 ]
補正後(配列の中身が更新されました)
補正後 Tokyo = [ 12 14 13 11 10 ]
補正後 Osaka = [ 13 14 13 ]配列を渡すと「同じ実体」を見ている(図で理解)
配列名を渡すと、関数側の仮引数 v は 呼び出し側配列の先頭を指すように扱われます。
だから、関数内で v[i] を更新すると、呼び出し側の配列も更新されます。

const を付けると「読むだけ」をコンパイラが保証してくれる
ここが今回の主役です。
const を付けるべきかの判断
| その関数は配列要素を書き換える? | 仮引数の宣言例 | 意味 |
|---|---|---|
| 書き換える | int v[] | 呼び出し側の配列を更新する可能性がある |
| 書き換えない(読むだけ) | const int v[] | 関数内で v[i] に代入できない(安全) |
つまり、show_array は読むだけなので const を付ける。
adjust_all は書き換えるので const を付けない。
このルールが分かれば、呼び出し側も安心して使えます。
命令(構文)の書式と「何をする命令か」
➀ const(型修飾子)
- 書式の例:const int v[]
- 何をする?
その変数(ここでは配列要素)を 書き換え禁止 にする指定です。
読み込みはOK、代入はNGになります。
➁ 配列を受け取る関数の仮引数
- 書式の例:int v[]、const int v[]
- 何をする?
「int型の配列(の先頭を指す情報)を受け取る」という宣言になります。
要素数は別引数 n で受け取るのが基本です。
➂ for 文
- 書式:for (初期化; 条件; 更新) 文
- 何をする?
指定回数ぶん、繰り返し処理を行います。配列処理の定番です。
➃ puts / printf
- puts:文字列を表示して改行
- printf:書式を指定して表示(数値などの整形ができる)
const を付けると起きる「エラー」の意味
たとえば show_array の中で、うっかり次のように書くと…
void show_array(const int v[], int n)
{
v[0] = 999; // 代入しようとした
}これは コンパイルエラーになります。
エラーの意味はシンプルで、
const で宣言された配列要素は変更できません
ということです。
つまり const を付けることで、間違いが実行前に止まるんです。強い。
n は「配列の要素数」ではなく「処理対象の個数」と考えるとスッキリする
今回の例では、わざとこうしました。
adjust_all(osaka, 2, -1);osaka は3要素あるのに、先頭2個だけ補正しています。
ここから分かる大事なポイントはこれです。
n の正体
| n の意味 | 例 | 何が起きる? |
|---|---|---|
| 配列の要素数そのもの | show_array(tokyo, 5) | 5個すべて表示 |
| 処理したい先頭の個数 | adjust_all(osaka, 2, -1) | 先頭2個だけ変更 |
なので説明としては、
- 「配列の全要素を…」という言い方もよくする(慣習)
- でも正確には「先頭 n 個の要素を…」という意味
この2つを頭の中で切り替えられると、配列関数が一気に読みやすくなります。
重要ポイント(ここだけは覚えておく)
- 配列を渡すと、関数側は呼び出し側配列を直接扱っているように見える。
- 書き換える関数は int v[]
- 読むだけの関数は const int v[](安心・安全・再利用しやすい)
- n は「処理対象の個数」と考えると応用が効く。
