ポインタの利用1(関数間のやりとり)

C言語初級カテゴリのロゴ画像C言語初級
スポンサーリンク

ポインタの宣言や仕組みが分かったとしてもどう利用したら良いかが分からないと実際に応用出来ません。
この記事では、ポインタの利用例をいくつか示します。

ポインタの基本については、以下の記事を参考にしてください。

ポインタについて
結論から言うと、ポインタ変数を使うと別の変数の内容を参照できます。 さらに大きな結論を言うなら、C言語を勉強するならポインタまで勉強しないと損です。
スポンサーリンク

main関数で宣言した変数内容を別の関数で値変更する

例えば「キーボードから入力した数値を2倍にして表示するプログラム」があったとします。
プログラムは以下のようになります。

#include <stdio.h>

int main(void){
	int x;

	printf("? ");
	scanf("%d", &x);

	x = x * 2;
	printf("%d\n", x);

	return 0;
}

実行イメージ

? 10 [Enter]
100

9行目の部分で変数xを2倍にしています。
この処理を別の関数baiの中で実行してみます。ポインタを使うと関数baiは次のように表現できます。

#include <stdio.h>

void bai(int *n)
{
	*n = *n * 2;
}

int main(void){
	int x;

	printf("? ");
	scanf("%d", &x);

	bai(&x);	/* 関数baiを実行 */
	printf("%d\n", x);

	return 0;
}

解説
main関数の14行目で関数baiを呼び出しています。
関数baiの引数に&x(変数xのメモリ上の番地)を指定しているため、受け取る関数側では、ポインタ変数の宣言をします。

void bai(int *n)

こうすると関数baiの中でmainで宣言している変数の内容にアクセスできます。

*n = *n * 2;

は、すなわち

x = x * 2;

を実行したことになります。

引数にポインタ変数を使わないでこのプログラムを作成した場合は、以下のようになります。

#include <stdio.h>

void bai(int n)
{
	n = n * 2;
}

int main(void){
	int x;

	printf("? ");
	scanf("%d", &x);

	bai(x);	/* 関数baiを実行 */
	printf("%d\n", x);

	return 0;
}

このプログラムは、問題なく実行可能です。
ただ、実行して関数baiに変数xの内容を受け渡すことは出来ても、main側の変数xの内容を変更することは出来ません。
あくまで変数xの内容が関数baiで参照できるのみです。

実行イメージ

? 10 [Enter]
10(main側の変数の値は変化しない

例1)金額を税込み価格に直す

次の例では、main関数で宣言されている変数kingakuの値を関数zeikomiにポインタ変数として引数渡しをして消費税込みの価格に書き換えています。

/* 46pointer.c ポインタの応用 */
#include <stdio.h>

void zeiKomi(int *k)
{
	*k = *k * 1.08;
}

int main(void)
{
	int kingaku;
	
	printf("金額は? ");
	scanf("%d", &kingaku);
	
	zeiKomi(&kingaku);
	
	printf("消費税込み: %d円\n", kingaku);
	
	return 0;
}

実行イメージ

金額は? 5000 [Enter]
消費税込み: 5400円

例2)数値配列を別の関数に渡す

配列名は実際はメモリ上に順番にならんだ変数の先頭番地を表しています。
そのため、配列の先頭番地を引数として渡すと受け取った関数で値の参照や代入ができることになります。

uriage.c: 配列データを全て表示する関数の引数にポインタを利用

#include <stdio.h>

void showData(int *uriage)
{
	int i;
	
	for(i=0; uriage[i] != -1; i++){
		printf("%10d円\n", uriage[i]);
	}
}

int main(void)
{
	int uriage[] = {1200, 550, 890, 50, 3000, 10800, 7800, 0, 100, 2100, -1};
	
	showData(uriage);
	
	return 0;
}

実行イメージ

1200円
550円
890円
50円
3000円
10800円
7800円
0円
100円
2100円

解説
関数showDataの呼び出し部分

showData(uriage);

は次のように記述しても同じ意味です。

showData(&uriage[0]);

すなわち配列名をプログラム上で使うとそれはその配列のメモリ上の先頭番地を表すことになります。
関数showDataでは、その配列の先頭番地をint *uriageとして受け取っています。
実際に配列内容にアクセスするときの記述がまさに配列の書き方になっていることに注目してください。
実は関数の引数などで配列をポインタ渡しした時の記述方法は2種類あります。

配列のポインタ2種類の書き方

通常の配列と同じ記述

for(i=0; uriage[i] != -1; i++){
	printf("%10d円\n", uriage[i]);
}

上記は、ポインタ本来の記述を用いて以下のようにも記述できます。

ポインタっぽい記述

for(i=0; *(uriage+i) != -1; i++){
	printf("%10d円\n", *(uriage+i));
}

例えば、配列a[0]は、配列aの先頭番地から0番目の内容という意味、すなわち*(a+0)で、a[2]配列aの先頭番地から2つ目の内容、すなわち*(a+2)という意味になります。

コメント