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

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]
20

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で参照できるのみです。

実行イメージ(main側の変数の値は変化しない

? 10 [Enter]
10

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

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

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

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

int main(void)
{
	int kingaku;

	printf("金額は? ");
	scanf("%d", &kingaku);

	zeiKomi(&kingaku);

	printf("消費税込み: %d円\n", kingaku);

	return 0;
}

実行イメージ

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

例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)という意味になります。

コメント

  1. 名無し より:

    最初のプログラム10の2倍は20では?

  2. kiryu より:

    こんにちは!kiryuです
    現在ポインタの勉強をしているのですが、配列との違いがイマイチ掴めません…
    配列名が配列の先頭要素へのアドレスを指すことは分かりました。
    どのような違いがあると考えればいいのでしょうか?

    • dennou より:

      配列とポインタの違いは無い」と考える方が分かりやすいかと思います。

      int a[10];
      int *p;
      
      p = a;    /* p = &a[0]; でも同じ */

      としたとき、

      変数pを使って配列aの2番目の要素内容を表すときは、

      *(p+1)

      と記述します。これはポインタ表現です。
      でも

      p[1]

      と記述してもa[1]を表すことになります。これは配列の記述と瓜二つです。
      記述方法が違うだけで、配列もポインタも同じメモリ上の並びあう要素を表現する方法と考えると良いのではないでしょうか。

  3. kiryu より:

    色々と調べて何となく同じ点と違う点が分かりました!
    ありがとうございましたー

    • dennou より:

      良かったですね!
      ポインタは使っていくうちに理解できてくると思いますので、どんどんプログラミングに利用してみると更に理解が深まっていくと思います。

タイトルとURLをコピーしました