main関数内で定義された構造体変数のアドレスを自作関数の引数に構造体型のポインタ変数をもちいて参照渡し(ポインタ渡し)をしてみます

ソーラー「はい、はいはい✋


先程のプログラムで

⇩  ⇩  ⇩    」


#include <stdio.h>


typedef struct Cube{

int no;

float tate;

float yoko;

float takasa;

}Cube;


void Cubedata2baiHyouji(Cube a){


a.no= a.no*2;

a.tate= a.tate*2;

a.yoko= a.yoko*2;

a.takasa= a.takasa*2;

/*ここでCube aに代入された


構造体変数の各メンバ変数の数値を2倍にします。*/


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

printf("%f\n" ,a.tate);

printf("%f\n" ,a.yoko);

printf("%f\n" ,a.takasa);

/*2倍になった

メンバ変数の値を表示します。*/

}


int main(void)

{


Cube cube1={1,7.0,7.0,7.0};


Cubedata2baiHyouji(cube1);

/*実引数である構造体変数cube1を

自作関数の仮引数である構造体変数aに代入しました。:*/


printf("%d\n" ,cube1.no);

printf("%f\n" ,cube1.tate);

printf("%f\n" ,cube1.yoko);

printf("%f\n" ,cube1.takasa);


return 0;

}

コンパイル結果

2        

14.000000    

14.000000    

14.000000    

1  🍎

7.000000 🍎

7.000000 🍎

7.000000 🍎


ソーラー「


main関数内で定義された構造体変数cube1が

自作関数の引数として定義された構造体変数aに値渡しされる様子が観察できました。


🍎の部分をみてみれば


main関数内で定義された構造体変数cube1のメンバ変数に格納された数値データに変化がないのが


わかりますね。


観察日記にかかなきゃ アレサ」


アレサ 「はい ソーラーさん


かきかき


6月30日


main関数内で定義された構造体変数cube1が

自作関数の引数として定義された構造体変数aに値渡しされることにより


main関数内で定義された構造体変数cube1🍃のメンバ変数に格納されていた数値データだけが


自作関数の引数として定義された構造体変数a🌳のメンバ変数に値渡しされました


値渡しですので


main関数内で定義された構造体変数cube1🍃のメンバ変数


cube1.no

cube1.tate

cube1.yoko

cube1.takasa


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

1

7.000000

7.000000

7.000000

自作関数の引数として定義された構造体変数a🌳のメンバ変数

a.no

a.tate

a.yoko

a.takasa

に渡されるだけで


main関数内で定義された構造体変数cube1🍃のメンバ変数


cube1.no

cube1.tate

cube1.yoko

cube1.takasa

自作関数Cubedata2baiHyoujiによる操作を受けないので


main関数内で定義された構造体変数cube1🍃のメンバ変数


cube1.no

cube1.tate

cube1.yoko

cube1.takasa


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

1

7.000000

7.000000

7.000000

のまま変化はありません


                       かしこ 」


ソーラー「このmain関数内で定義された構造体変数cube1🍃が、


だんだんと


🌳🌳🌳🌳🌳になっていくんだね。


楽しみだと思わないかい?」


アレサ「🍃から🌳🌳🌳🌳🌳へ(*´▽`*)


🌳🌳🌳🌳🌳だけでなく


🏡へも・・・


・・・それと🌹🌹🌼も育ててみたいとおもいますの。」


ソーラー 「いくらでもすきなだけ育てられると思うな


なんたって🍃はそこら中にたくさんあるからね。


さあて、まずは 構造体畑に今日も💧をまきますか・・」



ソーラー😊💦💦💦💦💦💦💦💦💦💦💦💦

      🍃🍃🍃🍃🍃🍃🍃🍃🍃🍃🍃🍃


アレサ 「それっ お水を召し上がれ


       ( ^^) _旦~~

💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧💧

 🍃🍃🍃🍃🍃🍃🍃🍃🍃🍃🍃🍃



💧                              💧


      💧           💧


    💧    🌞        💧           

                         💧

             💧

   💧        💧      💧                  💧          💧    💧           💧       

                🌞 

💧      💧            💧       

💧                    💧 


       💧             💧   💧


              💧

💧        💧      💧      💧


    💧    💧     💧      💧    💧

                   🌞 

💧        💧      💧         🌞 

                     🌞  

💧      💧  🌞💧            🌈🌈🌈 💧

                     🌈🌈

  🌞   💧        🌈🌈 💧  💧    💧  💧         🌈🌈  

         🌈🌈                  💧 💧   🌈🌈  💧     💧     💧   

   🌈🌈           💧       💧  

🌈🌈

🌈


ソーラー「よ~し 水やり終了


それでは さっきの続きにいこうかな。


main関数内で定義された


構造体変数cube1のメンバ変数に格納された数値データが


自作関数の引数として定義された構造体変数aのメンバ変数に


値渡しされる方法があるのであれば


構造体変数cube1のアドレス&cube1を


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


参照渡し(ポインタ渡し)する方法もあるわけなんだよね。


参照渡し(ポインタ渡し)するということは


構造体変数cube1のアドレスを代入するために


自作関数の引数にポインタ変数をつかうことになるよね?」


アレサ「はいっ、


こちらのプログラムが


構造体変数cube1のアドレス&cube1を


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


参照渡し(ポインタ渡し)の例となります


でも その前に


ポインタ変数について復習されますか」



ソーラー 「おおっ親切設計 じゃあ、お願いしようかな。」


アレサ「それではポインタ変数について


もう1度,御説明いたします。


ポインタ変数とは


変数のアドレスを格納するための変数です。


まず

(ここでは例として)


aの変数宣言

をおこないます。


次にポインタという変数をつくると


そのポインタという変数の中に変数aのアドレス(住所)


を格納することができます。


つまり『&a』(変数aのアドレス)をポインタという変数に


格納することができるわけです。


では実際に


そのポインタ変数を宣言してみましょう。


ポインタ変数を宣言するには


変数にしたい自分で選んだ任意の半角英数字の前に*をつけることで達成できます。


*印はそのあとにつづく文字をポインタ変数とするためにつけられるのです。


例えば


次の例のようになるわけです。


int* pta;  ( この場合ptaがint*型のポインタ変数として宣言されています。)

int* neko; (この場合nekoがint*型のポインタ変数として宣言されています。)



この例では、int*型のポインタ変数宣言がおこなわれていますね。


ここで注意するのは


今までは変数aが整数値データを格納するなら


int a;

とint 型を


変数bが実数値データを格納するなら


float b;

float 型を

というように


変数aや変数bに収められる数値データの種類によって


変数の型が決められてきました。


ですが、


ポインタ変数の型は


ポインタ変数におさめられる数値データの種類によって


ポインタ変数の型がきめられるわけではありません。


というか、


そもそもポインタ変数に格納されるのは変数のアドレスなので


格納されるのは常に整数値データです。

(%p出力変換指定子を用いてprintf出力表示した場合)

16進数の数値となっています


それではどのように


ポインタ変数の型はきめられるのでしょうか?


その仕組みはどのようなものになっているか・・というと


それは


int型の変数aのアドレス(&a)をポインタ変数に格納するのなら


int* pta; (ここではptaがint*型のポインタ変数宣言されています。)


であらわされるように


int*型(イントアスタリスク型)にポインタ変数pta

を格納するというきまりになっています。


float型の変数bのアドレス(&b)をポインタ変数に格納するのなら


float* ptb; (ここではptbがfloat*型のポインタ変数宣言されています。)


であらわされるように


float*型(フロートアスタリスク型)にポインタ変数ptb

を格納するというきまりになっています。


ポインタ変数がとりうる数値データの種類(実数か整数)によって


ポインタ変数が格納される型が


決まっているわけではありませんね。



ポインタ変数の復習は、ここまででよいでしたでしょうか?」


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


アレサ


「そして、今回は


構造体変数cube1のメンバ変数のアドレスを


自作関数の引数となっているポインタ変数に わたす


          参照渡し



行いたいというわけです。


そのためには 


まずは


構造体Cube型の構造体変数cube1の


アドレス(&cube1)を


を格納することのできる


ポインタ変数を作成したいというわけです。」


ソーラー「

自作関数の引数に

変数をもちいて

main関数内で定義された変数を

自作関数の引数に代入し

main関数内で定義された変数に格納されている数値データだけを

自作関数の引数に渡す方法は


            値渡し


自作関数の引数に

ポインタ変数をもちいて

main関数内で定義された変数のアドレスを

自作関数の引数に渡す方法は


         参照渡し(ポインタ渡し)


これは基本パターンだね。」


アレサ


「構造体Cube型の構造体変数cube1のアドレス(&cube1)を


格納できるポインタ変数を作製するには


次のポインタ変数宣言


Cube* pta;

(ここではptaのCube*型のポインタ変数宣言が実行されています。

ポインタ変数の名前はptaでもpttomatoでも何でも構いません)


のように


ポインタ変数ptaを


構造体変数cube1が格納されているCube型に対応して


Cube*型で宣言するというきまりがあります。


そうして 作製されたポインタ変数ptaに


構造体変数cube1のアドレス


&cube1を


pta=&cube1;


を実行して 代入します


このとき


構造体変数cube1は


構造体変数cube1のメンバ変数

cube1.no

cube1.tate

cube1.yoko

cube1.takasa

を管理しており


そのアドレス&cube1は


構造体変数cube1のメンバ変数

cube1.no

cube1.tate

cube1.yoko

cube1.takasa


の4つのアドレスを代表するアドレスとなっています


そして今


構造体変数cube1のメンバ変数

cube1.no

cube1.tate

cube1.yoko

cube1.takasa


に数値データ


1  

7.0 

7.0 

7.0 


が格納されています


その


構造体変数cube1のメンバ変数

cube1.no

cube1.tate

cube1.yoko

cube1.takasa

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


 🍋構造体変数cube1のアドレス&cube1が格納されているCube*型のポインタ変数ptaに🍋


       🍋アロー演算子->を用いて🍋



pta->no

pta->tate

pta->yoko

pta->takasa

あらわされるのでした。」


ソーラー「🌞そうだったね😊


           🌞pta=&cube1;🌞




        🌞Cube*型のポインタ変数ptaに🌞



🌞構造体変数cube1のアドレス&cube1が代入されたとき🌞


構造体変数cube1のメンバ変数


cube1.no

cube1.tate

cube1.yoko

cube1.takasa



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


pta->no

pta->tate

pta->yoko

pta->takasa



あらわされるんだったね。」


アレサ「


pta->no

pta->tate

pta->yoko

pta->takasa


を用いたプログラムは次のようになります



#include <stdio.h>


typedef struct Cube{

int no;

float tate;

float yoko;

float takasa;

}Cube;

int main(void)

{

Cube* pta;

Cube cube1={1,7.0,7.0,7.0};

pta=&cube1;

printf("%d\n" ,pta->no);

printf("%f\n" ,pta->tate);

printf("%f\n" ,pta->yoko);

printf("%f\n" ,pta->takasa);


return 0;

}

コンパイル結果

1

7.000000

7.000000

7.000000



ソーラー「アロー演算子 ->  ほんと矢の形なんだ。」


アレサ「ここまで 先のエピソードの復唱でした😊


それでは


Cube*型のポインタ変数ptaを自作関数の引数につかって


main関数内で定義された構造体変数cube1のアドレスを


自作関数の引数にポインタ参照渡し(ポインタ渡し)

してみましょう。


そのことをよく示す


プログラムは次のようになります」



#include <stdio.h>


typedef struct Cube {

int no;

float tate;

float yoko;

float takasa;

}Cube;


void Cubedata2bai(Cube* pta) {


pta->no = 2 * pta->no;

pta->tate = 2 * pta->tate;

pta->yoko = 2 * pta->yoko;

pta->takasa = 2 * pta->takasa;


/* 自作関数Cubedata2baiの定義の

void Cubedata2bai(Cube* pta)

このような


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


の表記方法はmain関数内で定義された変数のアドレスを


自作関数の引数に参照渡し(ポインタ渡し)するのに必要な表記法でしたね。


main関数内で定義された構造体変数cube1のアドレス&cube1を格納するために


ptaのCube*型のポインタ変数宣言を自作関数の()内で


おこないます 


構造体変数cube1のアドレスをCube*型のポインタ変数ptaに渡すことにより


構造体変数cube1のアドレス情報が


Cube*型のポインタ変数ptaに渡されることになります


このとき


構造体変数cube1のメンバ変数


cube1.no

cube1.tate

cube1.yoko

cube1.takasa


のアドレスのメモリに格納されている数値データは


ポインタ変数ptaを使って

pta->no

pta->tate

pta->yoko

pta->takasa


と表されます


構造体変数cube1のメンバ変数


cube1.no

cube1.tate

cube1.yoko

cube1.takasa


         アドレスのメモリに


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


ポインタ変数を使って

pta->no

pta->tate

pta->yoko

pta->takasa


とあらわされるので


pta->no

pta->tate

pta->yoko

pta->takasa


に操作を加えることにより


構造体変数cube1のメンバ変数


cube1.no

cube1.tate

cube1.yoko

cube1.takasa



       アドレスのメモリに


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


変更することができるようになります


ここでは


pta->no=2*pta->no;

pta->tate=2*pta->tate;

pta->yoko=2*pta->yoko;

pta->takasa=2*pta->takasa;


構造体変数cube1のメンバ変数のアドレスに格納されている数値データを


2倍になるよう自作関数を定義しています


*/


printf("%d\n", pta->no);

printf("%f\n", pta->tate);

printf("%f\n", pta->yoko);

printf("%f\n", pta->takasa);

}


int main(void)

{


Cube cube1 = { 1,7.0,7.0,7.0 };

/*cube1の構造体変数宣言,を初期化を行います*/


printf("%d\n", cube1.no);

printf("%f\n", cube1.tate);

printf("%f\n", cube1.yoko);

printf("%f\n", cube1.takasa);



Cubedata2bai(&cube1);

/*main関数で定義された構造体変数cube1のアドレス&cube1を


自作関数Cubedata2baiの引数である


Cube* pta(ポインタ変数pta)に代入して参照渡し(ポインタ渡し)を行います*/


printf("%d\n", cube1.no);

printf("%f\n", cube1.tate);

printf("%f\n", cube1.yoko);

printf("%f\n", cube1.takasa);


/*この4つのprintf命令文を実行して

構造体変数

cube1のアドレス&cube1が

自作関数にの引数に参照渡し(ポインタ渡し)されて

構造体変数cube1のメンバ変数

の格納している数値データが

自作関数の操作を受け

2倍になっているかどうかを確認しています。*/


return 0;

}


ビルド実行結果

1

7.000000

7.000000

7.000000

2

14.000000

14.000000

14.000000

2        🍈

14.000000    🍈

14.000000    🍈

14.000000    🍈



アレサ「


ビルド実行結果の4つの🍈を見てもわかるように


main関数内で定義された構造体変数cube1のアドレス&cube1を


自作関数の引数に


        「参照渡し(ポインタ渡し)」した結果


構造体変数cube1のメンバ変数に格納されていた数値データは


自作関数の操作をうけて2倍になっています。」


ソーラー「ようは


 

        「参照渡し(ポインタ渡し)」とは


 


自作関数内の引数として定義されたCube* ptaに(ポインタ変数ptaに)


main関数内で定義された構造体変数cube1の


           アドレス&cube1を


渡したように


自作関数の引数となっているポインタ変数に


main関数内で定義された変数のアドレスを渡すことなんだね。


そのとき


構造体変数cube1のメンバ変数



cube1.no

cube1.tate

cube1.yoko

cube1.takasa


のアドレスのメモリに格納されている数値データは


ポインタ変数ptaをつかって


pta->no

pta->tate

pta->yoko

pta->takasa


と表され


pta->no

pta->tate

pta->yoko

pta->takasa


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


pta->no

pta->tate

pta->yoko

pta->takasa

に操作を加えることにより変更することにより


構造体変数cube1のメンバ変数


cube1.no

cube1.tate

cube1.yoko

cube1.takasa


のアドレスのメモリに格納されている数値データを変更することができるってわけなんだね。🌞



これで


main関数内で定義された構造体変数に格納されている数値データも


自作関数をつかって変更を加えることができるようになったんだね。



このように構造体変数を自作関数の引数として参照渡し(ポインタ渡し)

する方法を使えば


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


瞬間的に移動させる


ようなことがことができるんだね」


アレサ 「できるとおもわれますの😊


次のプログラムをご覧ください


#include <stdio.h>


typedef struct Tamanoitidata{

float tate;

float yoko;

}Tamanoitidata;


/* 弾の縦、横の2つの位置データを格納するため

構造体Tamanoitidata

を作製しています */



void TamanoitidataHennkou(Tamanoitidata* pta){


/* ptaのTamanoitidata*型のポインタ変数宣言をおこなっています


この弾の位置を変更する自作関数TamanoitidataHennkouの


引数であるTamanoitidata*型のポインタ変数ptaに


後にmain関数内で定義される


弾の

縦、横の位置データを格納している


構造体変数tamanoitidata1のメンバ変数のアドレスを代表して


構造体変数tamanoitidata1のアドレス&tamanoitidata1を

参照渡し(ポインタ渡し)します。


参照渡し(ポインタ渡し)するのは


main関数内で定義された


構造体変数tamanoitidata1のメンバ変数に


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


変更することができるようにするためですね💖 */




pta->tate=pta->tate+5.0;

pta->yoko=pta->yoko+5.0;




/*👆ここでは


自作関数の引数であるTamanoitidata*型のポインタ変数ptaに


Tamanoitidata型の構造体変数tamanoitidata1のアドレスを渡す


参照渡し(ポインタ渡し)にすることが決まったので


あとは構造体変数tamanoitidata1に格納されている数値をデータを


どのように変化させるかを定義していきます


その際 ポインタ変数ptaを使って


構造体変数tamanoitidata1のメンバ変数に格納されている数値データを


変化させることになります。


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


    🌞構造体変数tamanoitidata1のアドレス&tamanoitidata1を渡す🌞


参照渡し(ポインタ渡し)にすることが決まったので


構造体変数tamanoitidata1のメンバ変数


tamanoitidata1.tate

tamanoitidata1.yoko


のアドレスのメモリに格納されている数値データは


ポインタ変数ptaに

アロー演算子->を用いて


pta->tate

pta->yoko


とあらわすことができます


ここでは


pta->tate=pta->tate+5.0;

pta->yoko=pta->yoko+5.0;


と記述することにより


構造体変数tamanoitidata1のメンバ変数


tamanoitidata1.tate

tamanoitidata1.yoko


のアドレスのメモリに格納されている数値データに5.0をたす操作を


自作関数TamanoitidataHennkouの定義としています。


*/


printf("%f\n" ,pta->tate);

printf("%f\n" ,pta->yoko);

}


int main(void)

{


Tamanoitidata tamanoitidata1={1.0,1.0};

/*構造体変数tamanoitidata1のメンバ変数


tamanoitidata1.tate

tamanoitidata1.yoko


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

1.0

1.0

に設定しました*/


printf("%f\n" ,tamanoitidata1.tate);

printf("%f\n" ,tamanoitidata1.yoko);



TamanoitidataHennkou(&tamanoitidata1);

/*構造体変数tamanoitidata1のアドレス&tamanoitidata1を


自作関数TamanoitidataHennkouの引数である


ポインタ変数宣言Tamanoitidata* ptaに代入しています


つまり ポインタ変数ptaに代入しています


ようは

自作関数の引数に

構造体変数tamanoitidata1のアドレス&tamanoitidata1を渡しておいて

あとは自作関数をつかって

構造体変数tamanoitidata1のメンバ変数に格納されている数値データを

変化させるという仕組みになっています


*/


printf("%f\n" ,tamanoitidata1.tate);

printf("%f\n" ,tamanoitidata1.yoko);


/*この最後の2つのprintf命令文で


main関数内で定義された

構造体変数tamanoitidata1のメンバ変数


tamanoitidata1.tate

tamanoitidata1.yoko


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


自作関数TamanoitidataHennkouの操作を受け


tamanoitidata1.tate=1.0

tamanoitidata1.yoko=1.0から


tamanoitidata1.tate=6.0

tamanoitidata1.yoko=6.0


になっているかを確認しています*/


return 0;

}


ビルド実行結果

1.000000

1.000000

6.000000

6.000000

6.000000

6.000000


アレサ「でてきました。(´▽`*)


ビルド実行結果をご覧になられてもお分かりいただけますように


main関数内で定義された

構造体変数tamanoitidata1のアドレス&tamanoitidata1が


自作関数の引数ptaに参照渡し(ポインタ渡し)され


自作関数TamanoitidataHennkouの操作を受けて


main関数内で定義された

構造体変数tamanoitidata1のメンバ変数


tamanoitidata1.tate 

tamanoitidata1.yoko



tamanoitidata1.tate=1.0 

tamanoitidata1.yoko =1.0


と格納されている数値データが


tamanoitidata1.tate=6.0

tamanoitidata1.yoko =6.0


と変化しました


このことは

ディスプレイ上にある


縦1.0

横1.0

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


自作関数の操作を受けて


縦6.0

横6.0

に移動することと


原理的にはおなじだとおもわれますの


これが値渡しなら


構造体変数tamanoitidata1のメンバ変数


tamanoitidata1.tate 

tamanoitidata1.yoko

自作関数の操作をうけず


tamanoitidata1.tate 

tamanoitidata1.yoko


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


tamanoitidata1.tate=1.0 

tamanoitidata1.yoko =1.0


のままとなり


ディスプレイ上の


弾の位置は


縦1.0

横1.0


のまま変化しないというわけです」


ソーラー「これを応用すれば


弾の位置を少しづつ移動させて


直線や曲線を描いて見せるというようなことも


できるというわけなんだね」


アレサ「そうですね😊」


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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

マイページ
読書の状況から作品を自動で分類して簡単に管理できる
小説の未読話数がひと目でわかり前回の続きから読める
フォローしたユーザーの活動を追える
通知
小説の更新や作者の新作の情報を受け取れる
閲覧履歴
以前読んだ小説が一覧で見つけやすい
新規ユーザー登録無料

アカウントをお持ちの方はログイン

カクヨムで可能な読書体験をくわしく知る