ポインタ渡しの具体例はmain関数内で定義された変数aのアドレスを自作関数内で定義されたポインタ変数ptxに代入することですね

🌞🌞🌞ポインタ渡しとは自作関数の引数にポインタ変数をつかい実引数のアドレスをポインタ変数に渡す方法のことなのです🌞🌞🌞

ソーラー「面白い仕組みになってるよね。


なんでこのような仕組みになっているのか?

👇


自作関数内で定義された変数xに


main関数内で定義された変数aを代入して自作関数による操作を加えても


main関数内で定義された、もとの変数aに格納されている値に変更を加えることはできない。



以前のエピソードでも見てきたように


このことはメモリにデータが蓄えられるという観点からみれば


とても自然なことだったね。


(これは値渡しと呼ばれる変数aから変数xへの


数値の受け渡し方法でしたね💖)


このように


自作関数の引数にmain関数内で定義された変数aを代入して


自作関数の操作を加えても


main関数内で定義されたaの値が変更できないとなると


自作関数をつくってもあまり使い道がないかもしれないね」



このことは


RPGゲームでいえば


あるゲームキャラクターのHPを自作関数にかけても


HPの量は 全く変化しないということになります



シューティングゲームでいえば


ある位置にある弾を別の位置に移動させようとして自作関数にかけても


弾の位置は 全く移動しないということになります


                    solarplexussより

                     



ソーラー

「そうだね


自作関数内で定義された変数xに


main関数内で定義された変数aを代入して自作関数による操作を加えても


main関数内で定義された、もとの変数aに格納されている値に変更を加えることはできない。



このシステムはどうなってるのか😝


もう1度


確かめてみようよ アレサ」


アレサ「はいっ


次のプログラムを観察してみます


#include <stdio.h>


void newmadefunction(int x)

{

x=x+5;

printf("%d\n",x);

}


int main(void){

int a=1;

newmadefunction(a);/*ここで自作関数に変数aを代入*/

printf("%d\n",a);

return 0;

}


コンパイル結果


EAZY IDECの場合

6

1


Visual Studioの場合

6

1



アレサ「上記のプログラムでは


変数aの持っている値1が変数xへ値渡しされる様子が観察できます。


つまり


自作関数内で


int x


と


変数宣言、作製された変数x

という名のついたメモリと


main関数内で


int a=1;

と

変数宣言、作製された変数a

という名のついたメモリ


は完全に独立しており


変数x

という名のついたメモリに


いくら


変数a

という名のついたメモリに格納されている数値1を代入したのち


x=x+5;


により

変数x

という名のついたメモリに格納されている値を

1から6に変更したとしても


変数a

という名のついたメモリに格納されている値は変化しないのでした。




このように


            値渡しとは



自作関数newmadefunctionを使って


変数aに格納されている値を変化させようとして


          newmadefunction(a);


を実行させても


 変数aが自作関数の操作をうけるわけではなく


 変数aに格納されている数値1だけ


が自作関数の引数xに渡されるシステムなのです


ですので


 変数aは自作関数の影響を受けることはなく


 変数aに格納されている数値は a=1のまま変わらず


 プログラム内の最後の命令文


 printf("%d\n",a);の


 コンパイル結果は

 1

 が表示されることになります」


ソーラー


「あはっ 変数aの値を6に変化させるために自作関数をつくっても


これでは自作関数作製の意味がなくなるよね もう💖


こまったちゃんだな~


どうしよっかな~~


このままでは


変数aに格納されている値を変更できないので


変数aに格納されている値を変更するには


自作関数を使わず


直接


main関数内で変数aに、操作を加えないといけなくなるかな


そのプログラムは


先のプログラムの自作関数の定義を消し


newmadefunction(a);


の部分を


a=a+5;

printf("%d\n",a);


にきりかえた


次のプログラムのようになる?かな?


#include <stdio.h>


int main(void) {

int a = 1;

a = a + 5;

printf("%d\n", a);

return 0;

}


コンパイル結果

EAZY IDECの場合

6


Visual Studioの場合

6


これで何とか変数aに格納されている値を


1から6にかえてprintf出力表示できました😝


このように


newmadefuncution(a);


が実行されても


aの格納している値を変更できないので


main関数内で


a=a+5;

printf("%d\n",a);


と記述しなければならなくなりますね😝


今の場合は


a=a+5;

printf("%d\n",a);


が短い命令文だったので


記述は簡単でしたが


長くて複雑な命令文のあつまりだったり


何回もこの部分を書かないといけない場合は


かなり手間がかかるかもしれないね😊😊😊


いやん」


アレサ「そうなの です


このような結果になっているのは


結局のところ


自作関数内で

int x

と


変数宣言、作製された変数x

という名のついたメモリと


main関数内で

int a=1;

と


変数宣言、作製された変数a

という名のついたメモリ


は完全に独立しているということが根本的な😊原因なのですね




値渡しのシステムでは


自作関数newmadefuncution(int x)の引数である


int xの部分に変数aを


newmadefuncution(a);


のように記述すると


変数aに格納されている数値データ1を変数xに渡すことはできますの」


ソーラー「では


自作関数をつかって


main関数内で変数宣言された


変数aに格納されている数値を変更するシステムはあるのかな?

                      

たとえば次のようなシステムはどうかな・・・


自作関数newmadefuncutionの引数である


変数xにmain関数内で変数宣言された変数aを


newmadefuncution(a);

と

記述すると


変数aに格納されている数値データ1を変数xに渡すことはできるんだったら


変数aに格納されている数値データ1を変数xに渡したのち


x=x+5;


を実行後


変数xに格納されることになった


数値6を


再び


変数xから


変数aに戻して代入するとか?



プログラムを記述すると


#include <stdio.h>


void newmadefunction(int x)

{

x = x + 5;

printf("%d\n", x);

}


int main(void) {

int a = 1;

newmadefunction(a);/*ここで自作関数に変数aを代入*/

printf("%d\n", a);

a = x;/*main関数内で変数宣言された変数aに自作関数内で

変数宣言された変数xを代入しようとしています。*/

printf("%d\n", a);

return 0;

}


ソーラー「

さあ、ビルド!」


ビルド実行結果



エラー C2065 'x': 定義されていない識別子です。

エラー (アクティブ) E0020 識別子 "x" が定義されていません


ソーラー「あ、そうか


a = x;/*main関数内で変数宣言された変数aに自作関数内で

変数宣言された変数xを代入しようとしています。*/


を実行しようとしても


xは自作関数内で作製された変数だから


main関数内で使用できないのか・・・


う~ん こまっちゃったな~」



アレサ


「はいっ


変数aに格納されている数値を変更する


例えば


変数aに格納されている数値に1を加えたいなら


a=a+1;


をおこなえばよいことになります」


ソーラー「はひ?」


アレサ


「はいっ😊


変数aに格納されている数値を変更する


例えば


変数aに格納されている数値に1を加えたいなら


直接


変数aをもちいて


a=a+1;


をおこなえばよいことになりますの


つまり


とても単純なことで


     

    🍓変数aと名前の付いたメモリに直接アクセスして🍓



      🍓格納されているデータをかきかえればよい🍓



ということになるんですの。」



solarplexusss「なにぃ」



アレサ「または


     🍓変数aに格納されている数値を変更する🍓


には


       🍓変数aという名前のつけられたメモリ🍓



に格納されている数値データを



          🍓変数aをつかって🍓


変更してやればよいというわけなんですの」



ソーラー「い、いや・・・まさにそうすれば


変数aに格納されている数値を変更することはできるんだけど・・・」


アレサ「例えば


変数aに格納されている数値に1を加えたいなら


a=a+1;


をおこなえば


変数aという名前のつけられたメモリ


に格納されている数値データに1を加えることができます。」


solarplexuss


「それはとても普通で自然な・・・」



ソーラー「まあ、そのとおりだよね」



アレサ「自作関数内で

int x

と


変数宣言、作製された変数x

という名のついたメモリと


main関数内で

int a=1;

と


変数宣言、作製された変数a

という名のついたメモリ


は完全に独立している以上


どのような値を


変数xに格納しても


変数aに格納されている数値に変化が起きることはありません。


ですので


変数aに格納されている数値を変更するのに


自作関数内で

int x

と


変数宣言し変数x


という名のついたメモリを作製することは


意味がないことになるのですの。」


solarplexuss「おお、ほんとだ」


アレサ「ということは


自作関数内で

int x

と


変数宣言し変数x

という名のついたメモリを作製することはやめ


最初から


自作関数内でも


main関数内で

int a=1;

と


変数宣言、作製された変数a


という名のついたメモリ


にアクセスして


変数aに格納されている数値を


直接


変更すればよいということになります。」


ソーラー「おお・・・」


solarplexuss「わおん🐕」


アレサ「それは


すでに学んできたポインタ変数を


自作関数の定義につかえば可能になるんですの


 ポインタ変数を自作関数の定義に用いたシステムでは      


 変数aのアドレスを自作関数の引数に渡すという方式をとっているため


自作関数の引数には


変数xでなく


変数aのアドレスを格納することができるポインタ変数ptxが用いられます


またまた


アドレスを格納するポインタ変数が登場してきます。」


ソーラー

「変数aのアドレスを自作関数の引数に渡すという方式?


どういうこと?


アレサちゃん、にゃお~んん。アレサちゃん🙀」


solarplexuss「わおん、わおん🐕」


アレサ


「はいっ😊はい


それでは


ここでポインタ変数のおさらいをしてみます😊


以下のプログラムでは


変数aのアドレスを


格納するためにptaのポインタ変数宣言を行っています


#include <stdio.h>


int main(void){

int a=1;

int *pta;/*😊ptaのポインタ変数宣言を行います😊*/

pta=&a;/*ポインタ変数ptaに変数aのアドレス&aを行い格納します*/


printf("変数aのアドレスは%pです。\n",&a);

printf("ポインタ変数ptaに格納された変数aのアドレス&aの値は%pです。\n",pta);

printf("変数aに格納されている数値は%dです。\n",*pta);

/*この*ptaの使い方がポイントです🌞*/

return 0;

}

コンパイル結果


変数aのアドレスは0019FF54です。

ポインタ変数ptaに格納された変数aのアドレス&aの値は0019FF54です。

変数aに格納されている数値は1です。




そして この場合のように


   🍒 ポインタ変数ptaに変数aのアドレス&aが格納されて 🍒


   🍒          はじめて            🍒


 🍒 *ptaは変数aに格納されている数値をあらわすのでしたね 🍒 

 

                                                               」


ソーラー「そうそう そうだった


そして


int *pta; は ptaのポインタ変数宣言


*pta は ポインタ 変数ptaが格納しているアドレスのメモリに


格納されている数値


今の場合


ポインタ変数ptaに変数aのアドレス&aが格納されているので


*pta は


変数aが格納している数値


をあらわしており


同じ*(アスタリスク)がついていても


int *pta;


と


*pta


では


意味合いがちがってたんだった」



アレサ「それでは😊


先程のプログラムをポインタ変数をつかって


書き換えてみます


先程のプログラム

👇

#include <stdio.h>


void newmadefunction(int x)

{

x=x+5;

printf("%d\n",x);

}


int main(void){

int a=1;

newmadefunction(a);/*ここで自作関数にaを代入*/

printf("%d\n",a);

return 0;

}


コンパイル結果

6

1


から


ポインタ変数を用いたプログラム

👇

#include <stdio.h>


void newmadefunction(int*ptx)

{

*ptx=*ptx+5;

printf("%d\n",*ptx);

}


int main (void){

int a=1;

newmadefunction(&a);

printf("%d\n",a);

return 0;

}


コンパイル結果

6

6



に変更しました。



変更したプログラムでは


先程の自作関数の定義


void newmadefunction(int x){

x=x+5;

printf("%d\n",x);

}

をポインタ変数ptxを使い


自作関数の定義


void newmadefunction(int*ptx){

*ptx=*ptx+5;

printf("%d\n",*ptx);

}

にかきかえていますね。


  

     newmadefunction(int*ptx)のint*ptx



にご注目ください



         main関数内で変数宣言された


     変数aに格納されている数値データを変更するためには


        自作関数 newmadefunctionの引数()に


      変数aのアドレスを代入することができるようにするために


              まず


           ptxのポインタ変数宣言


       int*ptxを引数()内に記述する仕組みとなっています。



そうして 変数aのアドレスがポインタ変数ptxに代入されると


               *ptxは


変数aのアドレスのメモリに格納されている数値を表すことになります


この*ptxを用いれば


変数aのアドレスのメモリにアクセスし


変数aのアドレスのメモリに格納されている数値を


変更することができます


この*ptxを自作関数の定義に用いることにより


*ptxを用いて変数aのアドレスのメモリにアクセスし


操作を加えることで


変数aのアドレスのメモリに格納されている数値を変更


つまり


変数aの格納している値を変更できます


すなわち


*ptx=*ptx+5;


は


a=a+5;


を実行することと等しくなるんですの


ソーラーさん」


ソーラー「🐕びくっ」


アレサ「


このように


main関数内で変数宣言された


変数aに格納されている数値を


変数aという名前が付けられたメモリに直接アクセスして


変更できるように


        変数aのアドレスを


自作関数の引数となっているポインタ変数に代入することを



         🌞ポインタ渡し🌞


と呼びます



そして


自作関数の引数にmain関数で定義された変数aのアドレスを


わたすのに


自作関数(ポインタ変数宣言);


この場合は


newmadefunction(int*ptx);


と記述するのはC言語のきまりとなっています


ここでポインタ変数宣言された


ポインタ変数ptxに変数aのアドレスが代入されると


*ptxは


変数aに等しくなる


つまり


変数aという名前のついたメモリに直接


アクセスすることができようになります。


自作関数の定義

void newmadefunction(int*ptx){

*ptx=*ptx+5;

printf("%d\n",*ptx);

}

は


変数aという名前のついたメモリに格納されている数値データが


自分の目的にそって変更されるよう


*ptxを用いて


*ptx=*ptx+5;


と


記述されているのがわかります。


この場合は


変数aという名前のついたメモリに格納されている数値データに


5を加えようとしているのですね。


*ptx=*ptx+5;


は


a=a+5;


が実行されているのと


等しいのです。」



ソーラー「🌞ポインタ渡し🌞とは


自作関数の引数に変数xを用い


変数xに変数aを代入するのでなく


自作関数の引数にポインタ変数ptxを用い


変数aのアドレスをポインタ変数ptxに渡すことなんだね。


そうすれば


*ptxは変数aに等しくなり


*ptxに格納されている数値を変更してやれば


変数aに格納されている数値が変更されるんだね


     もっとはっきり言えば


       💖💖💖最初から💖💖💖


       💖💖💖自作関数内でも💖💖💖


       💖💖💖main関数内でも💖💖💖



       💖💖💖変数aのメモリにしか💖💖💖



 💖💖💖このプログラムではアクセスしていないんだね。💖💖💖


」


アレサ「そうなんです


もうすこし


自作関数newmadefunctionの定義を見ていきましょう


*ptx=*ptx+5;

printf("%d\n",*ptx);


このように


*ptxに5を加えることにより


変数aに格納されている値に5を加えることができます


🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞

余談ですが


*ptxと書かれただけの


状態ではポインタ変数ptxはまだ初期化されていません


ですので


ポインタ変数ptxは初期化されていないと内部に


なんのアドレスかわからないモンスターアドレスを格納しています


ですので😊


このままでは 


*ptxは


初期化されていないポインタ変数ptxが


格納しているモンスターアドレスの場所のメモリに


格納されている数値を表してしまいます


ポインタ変数ptxに変数aのアドレスが


ptx=&aと


格納されて 


はじめて


*ptxは変数aに格納されている数値をあらわすことになります


🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞 🌞


そうして


ポインタ変数ptxに


ptx=&a;と


   🍎🍎🍎変数aのアドレス&aを代入すれば🍎🍎🍎


       


       🍎*ptxは変数aと全く等しくなり🍎



*ptxは変数aが格納している値1をもつことになります


別の言い方をすれば


🍎*ptxはポインタ変数ptxが格納しているアドレスの場所のメモリに🍎


     

       🍎🍎格納されている数値を表す🍎🍎


ので


ptx=&a;


と変数aのアドレス&aを代入すれば


*ptxはアドレス&aに格納されている数値1を表します


*ptx=1


ですね。


このとき


*ptx=*ptx+5;


のような操作は


a=a+5;


と全く等しくなりますので


*ptx=*ptx+5;


が実行されることにより


*ptx=6という値をもつということは


は


a=a+5;


が実行されることにより


a=6という値をもつということと


等しくなります。


別の言い方をすれば


*ptxは変数aと一緒で


ポインタ変数ptxが格納しているアドレス&aの場所のメモリに


アクセスすることができ

    


     🍎そのメモリに格納されている数値を表す🍎



ので


*ptx=*ptx+5;


が実行されると


*ptx=6


となり


変数aのアドレス&aのメモリに格納されている数値は6に変更されます


つまり


変数aに格納されている数値は6に変更されるのです


printf("%d\n",a);の


コンパイル結果も


6になっていますね


このようにして


値渡しではできなかったのですが


自作関数の引数であるポインタ変数ptxに


変数aのアドレス&aを渡し


main関数内で定義された変数aに


格納されている数値を1から6に変更することができます。


ポインタ変数にはこのような使い道があったのですね。」


ソーラー「このシステムは、結構つかいそうだね。」


アレサ「そうです。


自作関数をつかったプログラムでは


main関数内で作製された変数aに格納されている数値を


変更する必要がある場合が多く


いたるところに


この


参照渡しが登場してくるのですの」


ソーラー 「ははあん🌞 よくわかったよ


アレサ。


参照渡しとは


こういうことだったんだね


ポインタ変数を自作関数の引数に使わない値渡しと


ポインタ変数を自作関数の引数に使う参照渡しか・・・


さあ、😊これで


参照渡しを使って


シューティングゲームの弾の位置が


変更できるようになったってことかな?」


アレサ「RPGにでてくるキャラのステータス


のHPを変更することを例に考えてみます。


そこで


先程のプログラムの

👇

#include <stdio.h>


void newmadefunction(int*ptx)

{

*ptx=*ptx+5;

printf("%d\n",*ptx);

}


int main (void){

int a=1;

newmadefunction(&a);

printf("%d\n",a);

return 0;

}


コンパイル結果

6

6


自作関数名をnewmadefunctionからHeal

変数名aをHPにかえてみると


#include <stdio.h>


void Heal(int*ptx)

{

*ptx=*ptx+5;

printf("%d\n",*ptx);

}


int main (void){

int HP=1;

Heal(&HP);

printf("%d\n",HP);

return 0;

}


コンパイル結果

6

6


となり


変数HPが自作関数Healによって1から6に変更されているのがわかりますね


変数HPのアドレスの場所のメモリに格納されている数値を


自作関数Healによって6に変化させたというわけです」
























こそこそ........





























うちはだれかって?




うちはにゃお~んです。


ようは


変数aという名前の付いたメモリに格納されている数値を変更するには


変数aという名前の付いたメモリにアクセスするしか方法がないと


理解しましたにゃん。


ぷぷ


あたりまえだって?にゃ?


うちもそうおもうにゃん


だから


ここにかくれてしゃべってるにゃん。




  • Twitterで共有
  • Facebookで共有
  • はてなブックマークでブックマーク

作者を応援しよう!

ハートをクリックで、簡単に応援の気持ちを伝えられます。(ログインが必要です)

応援したユーザー

応援すると応援コメントも書けます