「C言語/関数」の版間の差分

削除された内容 追加された内容
647 行
#include "stdio.h"
 
// グロ-バル変数を使って、交換用の変数をswap外部と共有しようと意図しているが・・・
void swap(int a, int b){
int x;
int a;
int b;
 
void swap(int a,int b) {
x = a;
a = b;
671 ⟶ 675行目:
 
 
こう失敗する原因は、呼び出され側のswap()の引数で用いられている値を格納する変数(上記コード例の<code> swap(int a,int b) </code> のaおよびb )は、必ず型をつけて再宣言しないといけないのでローカル変数になってしまうので、その変数をグローバル変数に出来ないから、である。
こうなる原因は、呼び出し元main関数側の引数(実引数)の値が、呼び出され側の引数(仮引数)にコピーされたためである。
 
たとえグローバル領域で「a」「b」と同名の変数があっても、swap関数内では同名なだけの別変数としてのローカル変数「a」「b」が新たに関数swap内では用意されてしまう。
なお、子(呼び出し先)の void swap(int a, int b) の a, b の部分を「仮引数」と呼ぶ。
またなお、親(呼び出し元)の swap(a, b); の a, b の部分を「実引数」と呼ぶ。
 
なお、swap関数の引数を定義する際に、(再宣言しないつもり等で)型をつけない事はできない。
つまり、実引数の値が仮引数にコピーされている。
 
 
ユーザ定義関数内で変数の値を交換させるためには、一例として、下記のようにポインタを使ってmain関数の変数a,bを書き換える方法がある。
 
<syntaxhighlight lang="C">
700 ⟶ 703行目:
</syntaxhighlight>
 
この例は意図通りに動作する。何故なら、実引数のアドレスが仮引数にコピーされたためである。
<pre>
swap前のa=1, b=2
707 ⟶ 710行目:
と表示される。
 
ポインタを使うと成功する理由は、main実引数のアドレスが仮引数にコピーされたため、swap関数がmain関数の変数a,bにアクセスできているからである。(つまり、ポインタを介したswap関数内のa,bはもはやローカル変数ではなく、グローバル変数などにアクセスできる。)
例6のように実引数の値を仮引数にコピーすることを''値渡し''と呼ぶ。
 
例7のように実引数のアドレスを仮引数にコピーすることを''参照渡し''と呼ぶ。
 
なお、
:ポインタを使わない6「誤ったswap関数」のように実引数の値を仮引数にコピーすることを''値渡し''と呼ぶ。
:ポインタを使った7「正しいswap関数」のように実引数のアドレスを仮引数にコピーすることを''参照渡し''と呼ぶ。
<ref>値渡しと参照渡しという用語はよく使われるが、『JISX3010:2003』には出てこない。</ref>
 
----
なお、ユーザ定義関数を何も書かずに全てmain関数に書く方法を使えば、ポインタを使わずとも交換できる。
 
<syntaxhighlight lang="C">
//例 誤ったswap関数
#include "stdio.h"
 
int main(){
int a = 1, b = 2;
printf("swap前のa=%d, b=%d\n", a, b);
int x;
x = a;
a = b;
b = x;
printf("swap後のa=%d, b=%d\n", a, b);
}
</syntaxhighlight>
 
<pre>
swap前のa=1, b=2
swap後のa=2, b=1
</pre>
 
なお、ポインタも使わず、グローバル変数を使わずに下記のようにswap関数を書いても、交換できない。
 
<syntaxhighlight lang="C">
//例 誤ったswap関数
#include "stdio.h"
 
void swap(int a, int b){
int x;
x = a;
a = b;
b = x;
}
 
int main(){
int a = 1, b = 2;
printf("swap前のa=%d, b=%d\n", a, b);
swap(a, b);
printf("swap後のa=%d, b=%d\n", a, b);
}
</syntaxhighlight>
 
 
<pre>
swap前のa=1, b=2
swap後のa=1, b=2
</pre>
----
 
=== 関数の引数として配列を渡す ===