関数の引数に値を渡す場合、2つの方法があります。
値渡し
値渡しは、引数に数値を渡す、ごく普通の方法です。
#include <stdio.h>
int menseki(int teihen, int takasa);
void main(void) {
int ans=0;
int teihen=5;
int takasa=10;
ans = menseki(teihen, takasa);
printf("面積=%d\n", ans);
}
int menseki(int x, int y) {
return x * y / 2;
}
面積=25
この例では、menseki関数に実引数として
底辺5と高さ10を渡しています。
この5と10の値は、それぞれ、x、yに代入され、
menseki関数の処理を実行します。
ここで大切なのは、
x、yに代入された値を、仮に変更したとしても
変数teihenやtakasaの値は変わらないと言う事です。
関数内では仮引数とローカル変数の値しか変更できない
と言うのが普通です。
アドレス渡し
アドレス渡しは、ポインタ渡しとも言い、引数にアドレスを渡す方法です。
#include <stdio.h>
void menseki(int teihen, int takasa, int* p);
void main(void) {
int ans = 0;
menseki(5, 10, &ans);
printf("面積=%d\n", ans);
}
void menseki(int teihen, int takasa, int* p) {
p* = teihen * takasa / 2;
}
上の例では、menseki関数に実引数として
底辺5と高さ10とansのアドレスを渡しています。
面積を求めたら、ansのアドレスを使ってansに値を入れています。
関数内では仮引数とローカル変数の値しか変更できない
と言うのが、普通なんですが、値渡しの時と違い、
ポインタ機能を使って
関数外の変数ansの値を変更する事ができるのです。
構造体を使った値渡しとアドレス渡し
#include <stdio.h>
struct hito {
int age;
char blood[3];
};
void show1(struct hito p);
void show2(struct hito* p);
void main(void) {
struct hito tanaka;
tanaka.age = 30;
tanaka.blood[0] = 'A';
tanaka.blood[1] = '\0';
show1(tanaka);
show2(&tanaka);
}
void show1(struct hito p) {
printf("age = %d\n", p.age);
printf("age = %s\n", p.blood);
}
void show2(struct hito* p) {
printf("age = %d\n", p->age);
printf("age = %s\n", p->blood);
}
上の例では、構造体を使い、
それぞれ値渡しとポインタ渡しを行っています。
show1関数の値渡しでは、
構造体のメンバageとbloodをshow1関数の仮引数pに代入し、
関数内の処理が行われます。
この場合、int型のageとchar型3つで
7バイト分の値渡しが行われる事になります。
そして、show2関数のアドレス渡しでは、
tanaka構造体のポインタをshow2関数の仮引数pに代入し、
関数内の処理が行われます。
この場合、ポインタ型なので、
4バイト分のアドレス渡しが行われた事になります。
構造体のメンバがどれだけ増えても
アドレス渡しを行えば、一律4バイトです。
このように、構造体を使う場合は、
値渡しよりもアドレス渡しの方が処理が軽くなるのです。
構造体のポインタ渡しは、
構造体のメンバが多くなればなる程、絶大な威力を発揮します。
関数へ構造体を渡す場合は、
極力、アドレス渡しを使うようにしましょう。
値渡しの特徴
値渡しのみの引数で構成された関数は、
その関数内の変数しか変更しませんので(グローバル変数は除く)、
他の関数に影響を及ぼす事がなく、
安心、安全で管理しやすい関数となります。
アドレス渡しの特徴
一方、アドレス渡しを使うと、
渡されたアドレスを使って関数外の変数も変更可能です。
便利ではありますが、他の関数にも影響を与えるので、
注意しながら使わなければなりません。