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
のまま変化しないというわけです」
ソーラー「これを応用すれば
弾の位置を少しづつ移動させて
直線や曲線を描いて見せるというようなことも
できるというわけなんだね」
アレサ「そうですね😊」
新規登録で充実の読書を
- マイページ
- 読書の状況から作品を自動で分類して簡単に管理できる
- 小説の未読話数がひと目でわかり前回の続きから読める
- フォローしたユーザーの活動を追える
- 通知
- 小説の更新や作者の新作の情報を受け取れる
- 閲覧履歴
- 以前読んだ小説が一覧で見つけやすい
アカウントをお持ちの方はログイン
ビューワー設定
文字サイズ
背景色
フォント
組み方向
機能をオンにすると、画面の下部をタップする度に自動的にスクロールして読み進められます。
応援すると応援コメントも書けます