2.7.1 配列を関数に渡す方法 配列を引数に取る関数に配列を渡すとき、配列はポインタとして渡されます。この 規則から以下のことが導かれます。まず関数の呼び出しについて考えましょう。次の 配列 int a[] = { 1, 2, 3, 4, 5 }; を関数 func()に渡すとします。これが何を行う関数であるかその詳細に関わらず、 少なくとも次のような形式で呼び出せることが予想できます。 func( a, 5 ); 配列の名前は配列の先頭要素を指す定数ポインタを意味します。そして新たな規則「配 列はポインタとして関数に渡される」ことから、配列名で関数を呼び出すことができる はずです。 2番目の引数5とは配列の大きさ(次元)です。関数が受け取るのは配列の先頭アド レス値ですから、関数は元の配列の大きさについての情報を失っています。従って関数 の中で配列の要素を操作するには配列の大きさを関数に渡す必要があるでしょう。つま り関数のパラメータリストは、配列とその大きさの2つの引数を持たなければならない ことになります。 実際この推論は正しく、この場合の関数 func()の関数プロトタイプは次のように書 けて、 void func(int [], int); となります。ただしこの関数(まだ中身が決まっていない)は戻り値の無い void型だ としています。前のページで述べたように、関数プロトタイプがコンパイラに伝えるの は引数の数、型と順番ですから、コンパイラはプロトタイプの中の変数名を無視します。 ですから、パラメータリストで配列は、「 int a[] 」から名前を取った「 int [] 」 と書くことができます。もちろんわかりやすくするために名前を付けても構いません。 具体的な例で確かめましょう。次のプログラムは配列を関数に渡す方法と、ポインタ を使った値渡し(参照渡しのシミュレーション)の効果を示しています。
// lst02_10.cpp // 配列を関数に渡す実験プログラム #include <iostream.h> #include <iomanip.h> void func(int [], int); // 関数プロトタイプ宣言 int main() { int a[] = { 1, 2, 3, 4, 5}; int i; cout << "呼び出し側の配列 : a" << endl << "メモリ領域のサイズ: sizeof(a) = " << sizeof(a) << " バイト" << endl; cout << "配列の値:"; for(i = 0; i < 5; i++) cout << setw(3) << a[i]; func( a, 5 ); // 関数呼び出し cout << endl << "関数呼び出し後の配列の値:"; for(i = 0; i < 5; i++) cout << setw(3) << a[i]; cout << endl; return 0; } // 関数定義 void func(int x[], int size) { int i; cout << endl << endl << "関数が受け取った配列: x" << endl << "メモリ領域のサイズ: sizeof(x) = " << sizeof(x) << " バイト" << endl; cout << "配列の値:"; for(i = 0; i < size; i++) cout << setw(3) << x[i]; cout << endl << endl << "*** 関数の中で各要素の値をインクリメント ***" << endl; for(i = 0; i < size; i++) x[i]++; } |
呼び出し側の配列 : a メモリ領域のサイズ: sizeof(a) = 20 バイト 配列の値: 1 2 3 4 5 関数が受け取った配列: x メモリ領域のサイズ: sizeof(x) = 4 バイト 配列の値: 1 2 3 4 5 *** 関数の中で各要素の値をインクリメント *** 関数呼び出し後の配列の値: 2 3 4 5 6 |
2.7.2 constポインタとはなんだろうか 呼び出された関数が配列を参照するだけで書き換える必要がない場合は、関数の引数 の宣言に const を付けましょう。つまり「int *」の代わりに「const int *」と します。次の例は、配列要素をディスプレイに表示する関数です。
// lst02_11.cpp // 配列をプリントする関数 #include <iostream.h> void print(const int *, int); // 関数プロトタイプ宣言 int main() { int a[] = { 1, 2, 3, 4, 5}; print( a, 5 ); // 関数呼び出し return 0; } // 配列要素をプリントする関数の定義 void print(const int *x, int size) { for(int i = 0; i < size; i++) cout << "a[" << i << "] = " << x[i] << ", "; cout << endl; } |
a[0] = 1, a[1] = 2, a[2] = 3, a[3] = 4, a[4] = 5, |
2.7.3 2次元配列を関数に渡す 2次元配列の場合を考えます。2次元配列は、配列を要素に持つ配列です。ですから これを指すポインタは「配列へのポインタ」でした。またこの場合は行と列の2つの大 きさを関数に渡す必要があります。つまり次のような2次元配列 int a[10][20]; を関数に渡すには, void func(int [][20], int, int);// 配列表現 または void func(int (*)[20], int, int);// ポインタ表現 という関数になります。列の大きさ20は必ず必要です。次に示すのは、行列要素をデ ィスプレイに表示するプログラムです。関数のパラメータリストをポインタ形式で宣言 しています。
// matrix05.cpp //4×5行列を関数に渡す #include <iostream.h> const int ROW = 4; //行の次元 const int COL = 5; //列の次元 void print(const int (*)[COL], int, int); int main() { int mat[][COL] = { {11,12,13,14,15}, {21,22,23,24,25}, {31,32,33,34,35}, {41,42,43,44,45} }; print(mat, ROW, COL); return 0; } void print(const int (*a)[COL], int row, int col) { cout << "行列の表示\n"; for(int i = 0; i < row; i++){ for(int j = 0; j < col; j++) cout << " " << a[i][j]; cout << endl; //行の終わりに改行 } } |
行列の表示 11 12 13 14 15 21 22 23 24 25 31 32 33 34 35 41 42 43 44 45 |
Copyright(c) 1999 Yamada,K