自作関数の引数となっているポインタ変数宣言や配列宣言にmain関数内で作成された配列のアドレスを格納しているポインタ変数を参照渡し(ポインタ渡し)することができます 

ソーラー「


複数の数値データ1,2,3,4,5があるとするね


1つのポインタ変数宣言をつかって


その数値データ1,2,3,4,5を一度にメモリに格納できるよう


int* hairetu={1,2,3,4,5};

int* hairetu[]={1,2,3,4,5};


機能するよう


C言語をつくっておけばよかったんだけど・・・


1つのポインタ変数宣言をつかって


複数の数値データを1度にメモリに格納する方法をC言語の開発者は


つくらなかったのか・・・


(つくらなかったというよりは もともとint*型の変数はポインタ変数なのでアドレスしか格納することはできないので 作るのは無理💖といったほうが良いと思います)


int* hairetu

int* hairetu[]


によって生成される

hairetu[0]

hairetu[1]

hairetu[2]

int*型に格納されているアドレスなら格納できるというわけなんだね


🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞

実際に


ポインタ変数宣言

int* hairetu={1,2,3,4,5};

をつかった


次のプログラム


#include <stdio.h>

int main (void){

int* hairetu={1,2,3,4,5}

for(i=0;i<5;i++)

printf("%d\n",hairetu[i]);

return 0;

}


は、コンパイルエラーがでて


int* hairetu={1,2,3,4,5};


は機能しないことがわかります。


int* hairetu[]を用いたプログラムも


#include <stdio.h>

int main (void){

int *hairetu[]={1,2,3,4,5}

for(i=0;i<5;i++)

printf("%d\n",hairetu[i]);

return 0;

}


コンパイルエラーがでて


int *hairetu[]={1,2,3,4,5};


は機能しないことが


わかります。


🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞🌞


ソーラー「


しかし こうして


ポインタ変数宣言をつかって


データをメモリに格納するいろんなパターンを調べてみるのは


とてもおもしろいね。


だって


すこしづつだけど


なんとなくポインタ変数が使いこなせるような


気がしてくるからね


よし 次 いってみよ~~」


アレサ「はいっ


自作関数の引数にmain関数内で定義された配列hairetuのアドレスを格納しているポインタ変数を


代入するプログラムは


次のように記述していました。


#include <stdio.h>


void newmadefunction(int hairetu[]){

int i;

for(i=0;i<5;i++)

printf("%d\n",hairetu[i]);

}


int main (void){

int newhairetu[5]={1,2,3,4,5};

newmadefunction(newhairetu);


return 0;

}


コンパイル結果


1

2

3

4

5


アレサ「


このプログラムでは


自作関数newmadefunction内の引数( )に


次のように


void newmadefunction(int hairetu[])


int hairetu[]が記述されています。


いかがですか。


ここまでは覚えておられましたか」


ソーラー「int hairetu[]が干しイカににているのは


だいたい覚えてる」


アレサ「素敵です


このプログラムは


自作関数newmadefunction内の引数( )内に


配列宣言


int hairetu[]がつかわれていますが


               😊😊int hairetu[]に代わりに😊😊



                 ポインタ変数宣言


                 😊int* hairetu😊


を用いて


書き換えることができます。」


ソーラー「int* hairetuなんだね」


アレサ「では、自作関数newmadefunction内の定義の引数部分を


int hairetu[]の代わりに


int* hairetuを使って


書き換えてみます。

👇

#include <stdio.h>


void newmadefunction(int* hairetu){

int i;

for(i=0;i<5;i++)

printf("%d\n",hairetu[i]);

}


int main (void){

int newhairetu[5]={1,2,3,4,5};

newmadefunction(newhairetu);


return 0;

}


コンパイル結果


1

2

3

4

5


アレサ「この場合


void newmadefunction(int* hairetu)の


int* hairetuに


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


格納しているポインタ変数


newhairetu


が代入されることにより


つまり


ポインタ変数

hairetuには


newhairetu


が代入されます。


いいかえると


hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4


配列newhairetuの配列変数


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

がアクセスしている


メモリのアドレスを格納しているポインタ変数


newhairetu

newhairetu+1

newhairetu+2

newhairetu+3

newhairetu+4


が代入されているともいえます。


すると


配列変数


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

がアクセスしている


メモリのアドレスにアクセスできるようになります。


すなわち

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


同じアドレスのメモリにアクセスする配列変数となっているんですの。


そして


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

同じアドレスのメモリに


アクセスしている窓であり


同じアドレスのメモリが格納している数値データを表すことができます


また


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

同じアドレスのメモリに格納されている数値データを変更することができます


操作することができます。



今の状況を別のたとえでたとえるなら


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


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


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


この

ポインタ変数pta

ポインタ変数ptb

ptb=pta;


のように代入されると


ともに


変数aのアドレスが与えられたポインタ変数

pta

ptb

となり


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


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


このことは


ポインタ変数newhairetuがポインタ変数hairetuに代入されることに


相当します。



ポインタ変数newhairetuがポインタ変数hairetuに代入されると


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


同じアドレスのメモリにアクセスする配列変数となります。


ptaがポインタ変数newhairetu


ptbがポインタ変数hairetu


*ptaが


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


*ptbが


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

に相当するというわけですね。


ソーラーさん」





ソーラー「これは・・・( ̄ー ̄)ニヤリ




   🍓1つのポインタ変数宣言をつかって🍓


 🍓複数の数値データ(この場合1,2,3,4,5)をメモリに1度に取り込む方法はない🍓



のだけど


この例もそうだということだね。


だって


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


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

を通して

アクセスするか

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

を通してアクセスしているか


というだけのことだからね。


あらたに


自作関数の引数に


1つのポインタ変数宣言int* hairetuをつかって


複数の数値データ(この場合1,2,3,4,5)を


他のメモリに新たに1度に取り込んだわけではなく


もともとメモリに格納されている数値データに


他の方法


つまり


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


を使ってアクセスしただけのことなんだね。


だから


1つのポインタ変数宣言int* hairetuをつかって


ゼロから新たに


複数の数値データ(この場合1,2,3,4,5)をメモリに格納したとは言えないね。」



solarplexuss「わかったかもん!」



ソーラー「さらに別の言い方だと


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


例えば


main関数内で定義された


変数aのアドレスを格納したポインタ変数を


自作関数の引数であるポインタ変数に代入して


変数のアドレスを渡すことでした。



そして変数aのアドレスが格納されたポインタ変数を操作することにより 


変数aのアドレスのメモリに格納されている数値データを変更することができました。


ということは


最初から変数aのア|ドレスのメモリにだけ数値データは格納されていて《💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖》


ポインタ変数をつかって


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


変更しただけなのです。


ポインタ変数宣言をおこなったことにより


新たな変数が別にメモリ上に作製され


そこに数値データが格納されたわけではありません。」


solarplexuss「おおぉぉ・・よくわからんけど・・なんかいい・・」


ソーラー「


ポインタ変数宣言int* ptaをおこなって


作製されたポインタ変数ptaに変数aのアドレス&aを


pta=&a;

代入すれば


*ptaは変数aのもつ数値データを格納することになりますが


それは


変数aとは違う*ptaという変数が新たにメモリ上に作製され


そのメモリに


変数aのもつ数値データが格納されているわけではないってことだよね。


*ptaは変数aのアドレスを持つメモリにアクセスして


変数aのもつ数値データを表すことになったのだから



変数aのもつ数値データを格納しているのは


変数aのアドレスを持つメモリだけということになるんだね。」



solarplexuss「う~んいいね。


そこを もうひとおしして説明してもらえると・・」


ソーラー「そっか


じゃあ


別の説明をこころみてみるよ



自作関数


void newmadefunction(int* hairetu)の引数である


ポインタ変数宣言int* hairetuに


配列newhairetuのアドレスを持つ


ポインタ変数newhairetuが代入されると


hairetuに[]演算子を作用させた


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


のアドレスを格納しているポインタ変数


hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4



newhairetu

newhairetu+1

newhairetu+2

newhairetu+3

newhairetu+4

が代入されます


ですので


hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4

にアスタリスク演算子を作用させた


*hairetu

*(hairetu+1)

*(hairetu+2)

*(hairetu+3)

*(hairetu+4)

                

*newhairetu

*(newhairetu+1)

*(newhairetu+2)

*(newhairetu+3)

*(newhairetu+4)


をあらわすことになり


*newhairetu

*(newhairetu+1)

*(newhairetu+2)

*(newhairetu+3)

*(newhairetu+4)

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

に等しいので


*hairetu

*(hairetu+1)

*(hairetu+2)

*(hairetu+3)

*(hairetu+4)

                


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


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


格納することになります。



つまり

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


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


格納することになります。




*hairetu

*(hairetu+1)

*(hairetu+2)

*(hairetu+3)

*(hairetu+4)

は     

配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


と等しいのは前のエピソードでもやったかな?


根本的に


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


  🐤🐤🐤🐤🐤🐤🐤🐤今🐤🐤🐤🐤🐤🐤🐤🐤


配列hairetuのポインタ変数hairetuに格納されているアドレス💖💖💖💖💖💖💖💖💖💖💖💖💖💖のメモリにアクセスする窓であり


hairetu

hairetu+1

hairetu+2

hairetu+3

hairetu+4

に格納されているアドレスのメモリにアクセスする窓であり)



そのメモリに格納されている数値データをあらわすのでした。


だから


配列hairetuのポインタ変数hairetuに


配列newhairetuのアドレスを格納しているポインタ変数newhairetuが


代入されると



配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

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


格納することになります。



newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

同じメモリにアクセスしている窓であり


そのメモリが格納している数値データを格納しているんだね。」



solarplexuss「おおぉぉ・・なんかいい」


ソーラー「よ、よ~し


だから


まずmain関数内で


newhairetuの配列宣言


int newhairetu[5]={1,2,3,4,5};


が実行されると


あるメモリに


1

2

3

4

5


が格納されます.


次に


自作関数の引数部分内で


int* hairetu



ポインタ変数宣言がおこなわれ


ポインタ変数hairetuが生成され


配列newhairetuのアドレスをもつポインタ変数newhairetuが


ポインタ変数hairetuに代入されると


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]



              今


配列hairetuのポインタ変数hairetuに格納されているアドレスのメモリに


アクセスする窓であり


そのメモリに格納されている数値データをあらわすので




             今


配列hairetuのポインタ変数hairetuに格納されているのは


ポインタ変数newhairetuであり


ポインタ変数newhairetuは


配列newhairetuのアドレスを格納しているので


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


配列newhairetuのアドレスを持つメモリを先頭とするメモリ領域にアクセスし


そのメモリ領域に格納されている数値データをあらわすことになります。


このとき


配列newhairetuのアドレスを持つメモリを先頭とするメモリ領域は


1

2

3

4

5


を格納しているので


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


1

2

3

4

5

を格納することになります。


なので


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

同時に同じメモリにアクセスして


そのメモリに格納されている数値データを表しているというわけなんだ。


だから


もともと


あるメモリには


数値データ

1

2

3

4

5


が格納されているのはまちがいないんだけど


自作関数内で


void newmadefunction(int* hairetu)と


ポインタ変数宣言

int* hairetuがおこなわれて


生成されたポインタ変数hairetuに


ポインタ変数newhairetuが代入されると


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]



数値データ

1

2

3

4

5


格納することになったとしても


それは


あらたに別のメモリに


1

2

3

4

5


格納したことにはならないんだ。


もとから存在する


あるメモリに


数値データ


1

2

3

4

5

は格納されていて


ポインタ変数newhairetuがポインタ変数hairetuに代入されることにより


もとから存在する


あるメモリに


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]

アクセスする窓となり


あるメモリに格納されている

数値データ

1

2

3

4

5

をあらわすことになっただけなんだね。



             配列変数


             hairetu[0]

             hairetu[1]

             hairetu[2]

             hairetu[3]

             hairetu[4]


という


変数がメモリに作製され


あらたにそのメモリに

数値データ

1

2

3

4

5

が格納されたわけではないんだね。


どう?みんなの注目 僕にあつまったかな?」


アレサ「はいっ ソーラーさん😊」


solarplexuss「いい~~~~


もう1ど、もう1どぉぉぉ


その・・


説明をお願いしたいのです。」



ソーラー「もう、まかしてよ~~~


COME ON!!!


自作関数の引数として


int* hairetuと


hairetuのポインタ変数宣言をおこなって


配列newhairetuのアドレスnewhairetuを


ポインタ変数hairetuに代入すると


hairetuに[]演算子を用いた


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


配列newhairetuの配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

がアクセスしているメモリ


にアクセスすることになり


数値データ

1

2

3

4

5


を表すことになるのがポイントかな?


配列newhairetuの配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

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

1

2

3

4

5


にアクセスする窓であり


そのメモリに格納されている数値データ

1

2

3

4

5

をあらわしているんだね。


ちょっとおまけ


配列宣言、初期化

int newhairetu[5]={1,2,3,4,5};


の代わりに


配列宣言

int newhairetu[5];


を実行し


int newhairetu[5];

により作製された


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


数値データを

newhairetu[0]=1;

newhairetu[1]=2;

newhairetu[2]=3;

newhairetu[3]=4;

newhairetu[4]=5;

のように

代入したとします。


生成された配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


を通して

数値データ

1

2

3

4

5

はあるメモリに格納されています。


この場合も


newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

はデータにアクセスするための窓の役割をはたしています。





🍋  🍋  🍋  🍋  🍋  🍋  🍋  🍋  🍋


ところで


💖自作関数の引数部分で💖


int* hairetu

配列宣言された配列hairetuのアドレスを格納しているポインタ変数hairetuに


main関数内で

配列宣言された配列newhairetuのアドレスを格納したポインタ変数newhairetuを代入することはできますが


🍋main関数内で🍋

配列宣言された配列newhairetuのアドレスを格納したポインタ変数newhairetuに


main関数内で

配列宣言された配列newhairetu2のアドレスを格納したポインタ変数newhairetu2を代入することはできません。


ですので


main関数内の配列宣言


int newhairetu[5]={1,2,3,4,5};


によって


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]


数値データが

newhairetu[0]=1;

newhairetu[1]=2;

newhairetu[2]=3;

newhairetu[3]=4;

newhairetu[4]=5;

のように

が代入された場合


main関数内で

配列宣言された配列newhairetuのアドレスを格納したポインタ変数newhairetuに


main関数内で


int newhairetu2[5]={6,7,8,9,10};


配列宣言された配列newhairetu2のアドレスを格納したポインタ変数newhairetu2を


newhairetu=newhairetu2;


と代入して


配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

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



1

2

3

4

5

から

6

7

8

9

10



変更することはできません。


🍋  🍋  🍋  🍋  🍋  🍋  🍋  🍋  🍋



ソーラー「


もう1度


自作関数newmadefunctionの引数となっている


ポインタ変数宣言int* hairetuによって作製された


ポインタ変数hairetuに


main関数内で配列宣言された配列newhairetuのアドレスを格納している


ポインタ変数newhairetuが代入されると


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


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


つまり


配列newhairetuの配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

がアクセスしているメモリ



アクセスする窓になり


配列newhairetuの配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

がアクセスしているメモリ

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


を表すことになる


プログラムをみてみるかな?」


#include <stdio.h>


void newmadefunction(int* hairetu){

int i;

for(i=0;i<5;i++)

printf("%d\n",hairetu[i]);

}


int main (void){

int newhairetu[5]={1,2,3,4,5};

newmadefunction(newhairetu);


return 0;

}


コンパイル結果


1

2

3

4

5


ソーラー「


配列newhairetuのアドレスを格納しているポインタ変数newhairetu


ポインタ変数宣言int* hairetuによって


作製されるポインタ変数hairetu


に代入されることにより


hairetuに[]演算子を用いて作製された配列変数


hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]



配列newhairetuの配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

のアクセスしているメモリの格納しているデータを


あらわすことになります。



このことは


ポインタ変数ptaに変数bのアドレスを


pta=&b;


のように


代入すると


*ptaは変数bの格納している値をあらわすことになる関係と


一緒です。


ポインタ変数ptaはポインタ変数hairetuに相当し


変数bのアドレス&bは配列newhairetuのアドレスを格納している


ポインタ変数newhairetuに相当します。


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


*pta

に相当します。



自作関数の引数となっている配列hairetuのアドレスを格納している


ポインタ変数hairetuに


main関数内で定義された配列newhairetuのアドレスを格納している


ポインタ変数newhairetuが代入されるということは


pta=&b;


に相当します。


自作関数の引数となっているint* hairetuによって作製された


ポインタ変数hairetuに


main関数内で配列宣言された配列newhairetuのアドレスを格納している


ポインタ変数newhairetuが代入されると


配列変数

hairetu[0]

hairetu[1]

hairetu[2]

hairetu[3]

hairetu[4]


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


つまり


配列newhairetuの配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

がアクセスしているメモリ



アクセスする窓になり


配列newhairetuの配列変数

newhairetu[0]

newhairetu[1]

newhairetu[2]

newhairetu[3]

newhairetu[4]

アクセスしているメモリに

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


1

2

3

4

5


を表すことになります。


これは


ポインタ変数ptaが変数bのアドレス&bを与えられることにより


*ptaが変数bのアドレスに格納されている数値データをあらわすことに


なることに相当しているんです、ね


solarplexussさん」




solarplexuss「


この説明を・・・ 


待って


    待って 


        待って


待ちつづけていたんだよぉおぉぉお」


ソーラー「やったね!」

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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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