博士「ここをチェックじゃ」

さて、ポインタのイメージがつかめたところでその確認と、それからポインタが加減算できるということを覚える為に次からのプログラムを見るのじゃ。


ぷうさん

ポインタの足し算引き算かあ・・・メモリの中に入っている値同志の加減算だからそりゃできるよね、・・ん!


博士「?」

な~にを一人で納得しておるんじゃ?!


困った顔のぷうさん

糠味噌をしっかりこねてんの!


困った顔の博士

・・・・・・・こねすぎて中の材料を粉々にしてしまって消滅させたり、変なものと組み合わせないようにの。

ポインタと変数の関係

実行文

#include <stdio.h>
main()
{
   int a;
   int *p;
   a=10;
   printf("address=%d a=%d\n",&a,a);
   p=&a; //aのアドレスをポインタpに代入
   printf("address=%d *(address)=%d\n",p,*(p));
   *(p)=30;  //*(3572)だから中に30を代入、aの値も30になる
   printf("address=%d *(address)=%d\n",p,*(p));
   printf("address=%d a=%d\n",&a,a); 
}

実行結果

address=3572 a=10
address=3572 *(address)=10
address=3572 *(address)=30
address=3572 a=30

変数を使ったプログラム

博士「ここをチェックじゃ」

これはポインタを使っていないんじゃが、使わない場合のサンプルとしてじゃ。

実行文

#include <stdio.h>
main()
{
   int data[4]={10,20,30,-1};
   int i;
   int i=0;
   while (data[i]>=0) {
      printf("data=%d\n",data[i]);
      i=i+1;
   }
}

実行結果

data=10
data=20
data=30

ポインタを使ったプログラム

博士「ここをチェックじゃ」

上のプログラムにポインタを導入してみると下の様になるぞい。

実行文

#include <stdio.h>
main()
{
   int data[4]={10,20,30,-1};
   int *pointa;
   pointa=&data[0];
   while (*(pointa)>=>=0) {
      printf("data=%d\n",*(pointa));
      pointa=pointa+1;
   }
}

実行結果

data=10
data=20
data=30







引数の渡り方を調べるプログラム

実行文

include <stdio.h>
void kansu(int kazu1,int kazu2);
main()
{
   int kazu1=10;
   int kazu2=20;
   printf("1:kazu1(address:%d)=%d ",&kazu1,kazu1);
   printf("kazu2(address:%d)=%d/n",&kazu2,kazu2);
   kansu(kazu1,kazu2);
   printf("2:kazu1(address:%d)=%d ",&kazu1,kazu1);
   printf("kazu2(address:%d)=%d/n",&kazu2,kazu2);
}

void kansu(int kazu1,int kazu2)
{
   printf("3:kazu1(address:%d)=%d ",&kazu1,kazu1);
   printf("kazu2(address:%d)=%d/n",&kazu2,kazu2);
   kazu1=80;  //kazu1の値を変更
   kazu2=90;  //kazu2の値を変更
   printf("4:kazu1(address:%d)=%d ",&kazu1,kazu1);
   printf("kazu2(address:%d)=%d/n",&kazu2,kazu2);
}

実行結果

1:kazu1(address:3668)=10 kazu2(address:3666)=20
3:kazu1(address:3658)=10 kazu2(address:3660)=20
4:kazu1(address:3658)=80 kazu2(address:3660)=90
2:kazu1(address:3668)=10 kazu2(address:3666)=20

チェックポイント

博士「ここをチェックじゃ」

分かるかな?mainとkansu関数の中で使われているkazulとkazu2は、名前は同じでも異なった変数なんじゃ。アドレスが違っとるじゃろう?

kansu関数が呼ばれると、引数に書かれたkazu2とkazu2の値がkansu関数のkazu1,kazu2にコピーされるんじゃ。
じゃが、kansuの中で変更された値はmainには返らない。
当たり前じゃ、アドレスが違うんじゃからの。


ぷうさん

ほうほう、双子だと思っておこう。


博士「Good!」

このプログラムのように・・・

引数の値だけコピーして関数に渡す事を「値渡し」と呼ぶんじゃ。

一方、変数のアドレスを関数のポインタに渡す方法を「アドレス渡し」と呼び、
これじゃと、呼んだ側の変数も変更できるのじゃ。

配列を関数に渡すプログラム

博士「ここをチェックじゃ」

今度は配列の取り扱いじゃ。

実行文

include <stdio.h>
void keisan(int data[]);  //注1
main()
{
   int data[]={10,20,30,40,50};
   int i;
   printf("\n main1 ");
   for (i=0;i<5;i=i+1) {
      printf("(%d)%d ",&data[i],data[i]);
   }
   keisan(data);
   printf("\n main2 ");
   for (i=0;i<5;i=i+1) {
      printf("(%d)%d ",&data[i],data[i]);
   }

}

void keisan(int data[])  //注2
{
   int i;
   printf("\n kansu1 ");
   for (i=0;i<5;i=i+1) {
      printf("(%d)%d ",&data[i],data[i]);
   }
   data[1]=80;
   data[3]=90;
   printf("\n kansu2 ");
   for (i=0;i<5;i=i+1) {
      printf("(%d)%d ",&data[i],data[i]);

   }
}

注1・・・void keisan(int *data);でもOK
注2・・・void keisan(int *data)でもOK

実行結果

main1 (3580)10 (3582)20 (3584)30 (3586)40 (3588)50
kansu1 (3580)10 (3582)20 (3584)30 (3586)40 (3588)50
kansu2 (3580)10 (3582)80 (3584)30 (3586)90 (3588)50
main2 (3580)10 (3582)80 (3584)30 (3586)90 (3588)50

チェックポイント

博士「ここをチェックじゃ」

配列はその先頭アドレスがポインタに渡るのじゃ。
そして、配列名は定数じゃからアドレスの変更はできんが、ポインタは変数じゃからアドレスを更新することができるのじゃ!!
つまり関数内では、配列名をポインタ変数としてアドレスを変更させることができるんじゃよ。


ぷうさん「OK」

先頭が渡るだけだから、他の値を見る時は更新させるんだね。ふむふむ。

その四 ポインタのまとめへ

二日目 ポインタについて 目次

一日目へ

ぷうさんの七日間戦争 二日目

三日目へ