6-3 実引数と仮引数

この記事は約6分で読めます。

実引数と仮引数の関係

関数を定義する時に指定する引数のことを仮引数と言い、実際に関数を呼び出すときに指定する引数のことを実引数と言います。

#include <stdio.h>
void printint(int a);
int nijou(int n);
int main(void){
	int ans;
	puts("main関数です。");
	printint(3);
	ans=nijou(5);
	printf("nijou(5)の戻り値:%d\n",ans);
	return 0;
}
void printint(int a){
	printf("print関数です。a=%d\n",a);
}
int nijou(int n){
	int ans;
	puts("nijou関数です。");
	ans=n*n;
	return ans;
}

これは前回は扱ったソースコードです。仮引数を、実引数をで表しています。関数が呼び出されるときは、実引数の値が仮引数にコピーされて実行されます。

#include <stdio.h>
void warizan(int a,int b,int shou,int amari);
int main(void){
	int p=10,q=3,shou=0,amari=0;
	printf("warizanを呼び出す前:p=%d,q=%d,shou=%d,amari=%d\n",p,q,shou,amari);
	warizan(p,q,shou,amari);
	printf("warizanを呼び出した後:p=%d,q=%d,shou=%d,amari=%d\n",p,q,shou,amari);
	return 0;
}
void warizan(int a,int b,int shou,int amari){
	if (a<0||b<=0) return;
	shou=a/b;
	amari=a%b;
	printf("warizan:a=%d,b=%d,shou=%d,amari=%d\n",a,b,shou,amari);
}

実行結果

warizanを呼び出す前:p=10,q=3,shou=0,amari=0
warizan:a=10,b=3,shou=3,amari=1
warizanを呼び出した後:p=10,q=3,shou=0,amari=0

このプログラムでは関数warizanが三つ目と四つ目の仮引数に値を代入しています。しかし、仮引数は実引数のコピーなので関数warizanで値を代入してもmain関数の元々の変数には影響を及ぼしません。また、ある関数の中で宣言した変数はその関数の中でしか使えません。つまり、関数warizanからmain関数の変数にアクセスすることや、実引数の値の変更はできません。

引数が配列の場合

関数の引数には配列を指定することもできます。配列を引数として受け取る場合は引数の型を配列にします。

#include <stdio.h>
void viewHairetsu(int ary[5]);
void viewHairetsu2(int ary[],int n);
void viewHairetsu3(int *ary,int n);
int main(void){
	int i,mat[5]={0,1,2,3,4};
	viewHairetsu(mat);
	viewHairetsu2(mat,5);
	viewHairetsu3(mat,5);
	return 0;
}
void viewHairetsu(int ary[5]){
	int i;
	puts("viewHairetsu");
	for (i=0;i<5;i++) printf("mat[%d]=%d\n",i,ary[i]);
}
void viewHairetsu2(int ary[],int n){
	int i;
	puts("viewHairetsu2");
	for (i=0;i<n;i++) printf("mat[%d]=%d\n",i,ary[i]);
}
void viewHairetsu3(int *ary,int n){
	int i;
	puts("viewHairetsu3");
	for (i=0;i<n;i++) printf("mat[%d]=%d\n",i,ary[i]);
}

実行結果

viewHairetsu
mat[0]=0
mat[1]=1
mat[2]=2
mat[3]=3
mat[4]=4
viewHairetsu2
mat[0]=0
mat[1]=1
mat[2]=2
mat[3]=3
mat[4]=4
viewHairetsu3
mat[0]=0
mat[1]=1
mat[2]=2
mat[3]=3
mat[4]=4

関数viewHairetsuでは引数にint型の要素を5つ持つ配列を受け取ります。それに対して、関数viewHairetsu2では一つ目の引数で配列の要素数を省略しています。そして二つ目の引数として配列の要素数を受け取ります。この書き方の方が、配列の要素数が5でなくても対応できるので汎用性があります。ちなみに、要素数を省略して配列を受け取る場合はアスタリスク*を用いて関数viewHairetsu3ように米印を使って書くこともできます。

先ほど関数の仮引数は実引数からコピーされるものと書きました。引数に変数を取るときは何か値を代入しても、元の実引数の変数には影響を与えません。しかし配列の場合は実引数と仮引数の配列が全く同じものとなります。つまり、配列を引数として受け取る場合は仮引数の配列の要素を変更すると呼び出し元の実引数の配列の要素も変わります。

#include <stdio.h>
void setHairetsu(int ary[5]);
int main(void){
	int i,mat[5]={0,1,2,3,4};
	for (i=0;i<5;i++){
		printf("mat[%d]=%d\n",i,mat[i]);
	}
	setHairetsu(mat);
	puts("関数setHairetsuを呼び出しました。");
	for (i=0;i<5;i++){
		printf("mat[%d]=%d\n",i,mat[i]);
	}
	return 0;
}
void setHairetsu(int ary[5]){
	int i;
	for (i=0;i<5;i++) ary[i]=0;
}

実行結果

mat[0]=0
mat[1]=1
mat[2]=2
mat[3]=3
mat[4]=4
関数setHairetsuを呼び出しました。
mat[0]=0
mat[1]=0
mat[2]=0
mat[3]=0
mat[4]=0

関数の引数が配列の場合、*をつかって表せる理由および配列を受け取る時に仮引数と実引数が同じものになる理由は第8章で説明します。

まとめ

C 言語では関数を呼び出す際には実引数の値が仮引数にコピーされて実行される。

よって、関数内で仮引数の値を変えても呼び出し元の数値が変わることはない。

しかし、配列の場合は呼び出し元の数値も変わってしまう。これは配列の場合はコピーされるのではなくもともとの配列そのものが渡されるからである。

コメント