次は配列の受け渡しについて説明します。
配列を渡す方法は何通りかあるのですが、まずはイメージし易い方法を書きます。
とりあえず、配列を含んだmain関数を作ります。
<sample program 139-00>
#include <stdio.h> #define DATA 5 int main(void) { int data[DATA] = { 3, 6, 9, 12, 15 }; return 0; } |
この配列の中身を表示する関数を作ることにしましょう。
プロトタイプ宣言は↓の通りです。
void ShowArray(int data[DATA]); |
引数の所に、
int data[DATA] |
と書いてありますが、ここで必要な情報は
型 配列名(何でも良い) 要素数
の3つです。
配列名は何でも良いと書いてありますが、今回は元のデータ名と同じ名前にしています。
関数の本体は↓のようにします。
void ShowArray(int data[DATA]) { int i; for (i = 0; i < DATA; i++) { printf("%3d", data[i]); } printf("\n"); } |
関数では、本体と同じように添え字を使って配列にアクセス出来ます。
添え字用の変数は関数内で宣言しています。
※関数内でしか使わない変数は、関数内で宣言するようにしましょう。
#defineで設定した「DATA」も、main関数の外で宣言しているためShowArray関数でも使うことが出来ます。
呼び出しも含めたプログラム全体を完成させましょう。
#include <stdio.h> #define DATA 5 void ShowArray(int data[DATA]); int main(void) { int data[DATA] = { 3, 6, 9, 12, 15 }; ShowArray(data); return 0; } void ShowArray(int data[DATA]) { int i; for (i = 0; i < DATA; i++) { printf("%3d", data[i]); } printf("\n"); } |
<実行結果>
3 6 9 12 15 続行するには何かキーを押してください・・・
ShowArray関数の呼び出しは、
ShowArray(data); |
となっています。
以前説明しましたが、配列名は「配列の先頭のアドレス」を指しています。
つまり、配列は「アドレス渡し」になります。
説明するために引数の配列名を変えてみます。
<sample program 139-02>
#include <stdio.h> #define DATA 5 void ShowArray(int receive[DATA]); int main(void) { int data[DATA] = { 3, 6, 9, 12, 15 }; ShowArray(data); return 0; } void ShowArray(int receive[DATA]) { int i; for (i = 0; i < DATA; i++) { printf("%3d", receive[i]); } printf("\n"); } |
main関数内で、配列dataの先頭のアドレスを表示し、ShowArray関数内で、配列receiveの先頭のアドレスを表示してみます。
<sample program 139-03>
#include <stdio.h> #define DATA 5 void ShowArray(int receive[DATA]); int main(void) { int data[DATA] = { 3, 6, 9, 12, 15 }; printf("data = %p\n", data); ShowArray(data); return 0; } void ShowArray(int receive[DATA]) { int i; printf("receive = %p\n", receive); for (i = 0; i < DATA; i++) { printf("%3d", receive[i]); } printf("\n"); } |
<実行結果>
data = 00DAF968 receive = 00DAF968 3 6 9 12 15 続行するには何かキーを押してください・・・
※実行結果(アドレス部分)は毎回変わる可能性があります。
dataもreceiveも同じアドレスを指しています。
どのように動作しているか図にしてみます。
まずは、配列dataがメモリに格納されています。
配列data メモリ +--------+ 00DAF968番地 | 3 | +--------+ 00DAF96C番地 | 6 | +--------+ 00DAF970番地 | 9 | +--------+ 00DAF974番地 | 12 | +--------+ 00DAF978番地 | 15 | +--------+
int型の配列なので、1つのデータに4バイト分の領域が割り当てられいます。
ShowArray関数では、receiveという名前で引数を受け取るようになっています。
このreceiveは見た目は配列の宣言ですが、中身はポインタ変数です。
+--------+ receive | | +--------+
ShowArray関数を呼び出す際に、配列dataの先頭のアドレスを渡していますので、
+--------+ receive |00DAF968| +--------+
このよう番地を受け取って、間接的に元のデータにアクセスをしています。
間接的に元のデータを扱うため、添え字を使うことで配列のイメージを崩さず使うことが出来ます。
さて、配列はアドレス渡しということを説明しましたが、アドレス渡しということは、関数で中身を書き換えると元のデータも書き換わる、ということですね。
試してみましょう。
<Sample Program 139-01>に新しい関数を付け加えましょう。
新しい関数は、配列の中身をすべて2倍するTwiceという関数にします。
プロトタイプ宣言
void Twice(int data[DATA]); |
本体
void Twice(int data[DATA]) { int i; for (i = 0; i < DATA; i++) { data[i] *= 2; } } |
受け取った配列の中身を2倍しています。
それでは、main関数のShowArray関数の前にTwiceを呼び出すコードを加えて実行してみましょう。
<sample program 139-04>
#include <stdio.h> #define DATA 5 void ShowArray(int data[DATA]); void Twice(int data[DATA]); int main(void) { int data[DATA] = { 3, 6, 9, 12, 15 }; Twice(data); ShowArray(data); return 0; } void ShowArray(int data[DATA]) { int i; for (i = 0; i < DATA; i++) { printf("%3d", data[i]); } printf("\n"); } void Twice(int data[DATA]) { int i; for (i = 0; i < DATA; i++) { data[i] *= 2; } } |
<実行結果>
6 12 18 24 30 続行するには何かキーを押してください・・・
結果を見てわかる通り、元のデータが書き換わっています。
配列については、アドレス渡しであり、値渡しをしようとすると非常に面倒なことになります。
※今のところ配列の値渡しは必要ないと思いますので、ここでは説明しません。
ところで、単純に配列の先頭のアドレスを渡しているのであれば、普通のポインタ変数でも受け取れそうです。
<Sample Program 139-01>のShowArray関数の引数を
int *pData |
に変えて動かしてみましょう。
<sample program 139-05>
#include <stdio.h> #define DATA 5 void ShowArray(int *pData); int main(void) { int data[DATA] = { 3, 6, 9, 12, 15 }; ShowArray(data); return 0; } void ShowArray(int *pData) { int i; for (i = 0; i < DATA; i++) { printf("%3d", pData[i]); } printf("\n"); } |
<実行結果>
3 6 9 12 15 続行するには何かキーを押してください・・・
ポインタ変数なので、名前の先頭に「p」を付けて「pData」としました。
先頭アドレスを受け取った後で、
pData[i] |
と添え字を付けることで、配列の中身にアクセス出来ています。
int data[DATA] |
で受け取るのと、
int *pData |
で受け取ることは結果的には同じことだということです。
ただ、個人的には
int *pData |
という書き方は、変数のアドレスを渡しているのか、配列の先頭のアドレスを渡しているのか区別が付きませんので避けたいと思います。
ポインタ変数について、もう少し詳しく知りたい方は「ポインタ変数について」を読んでください。
次回は2次元配列について書きます。