配列のポインタ変数とは一体何のことでしょうか?

ここで ソーラーさんは皆を笑わせようとおもいっきり😋間違ってきます。


ご注意ください。




アレサ 「ではでは(^^)


変数aのアドレス&aをポインタ変数ptaに格納できたところで


配列とポインタ変数はどのような関係になっているのでしょう?


考察してみましょう(^^)ね、ソーラーさん」


ソーラー「ええっ😝😝😝


配列とポインタ変数の関係?????


?????

?????


はい?なんのこと?


まるで

きゅうりとポテトチップスの関係を聞かれてるみたいだ・・


なんの関係もな~し


配列とポインタ変数の関係はなしです!


これで終了


配列とポインタ変数の関係は簡単です!


いいね。 アレサ」


アレサ 「はう?」


ソーラー 「い、いや、ちょっといってみただけなんだよっ


はうあうあうあ


い、いや~~~


と、とにかく


配列は確か・・・


例えば int hairetu [ ]={1,2,3};

と配列宣言、初期化したら


この配列hairetu内に自動的に


3つの配列変数

hairetu [0]

hairetu [1]

hairetu [2]

ができ


数値1,2,3が、それぞれ

配列変数

hairetu[0]には1

hairetu[1]には2

hairetu[2]には3


が格納されるシステムだった。

______________________________________________

配列宣言、初期化を

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

ではなく


もっと丁寧に

int hairetu[3]; (要素数3)

hairetu[0]=1;

hairetu[1]=2;

hairetu[2]=3;


と記述する方法もあるね。

______________________________________________


配列を使えば


int a=1;

int b=2;

int c=3;

👆

このようにa,b,cのint型変数宣言&初期化をおこなわなくても


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


で済むから便利なんだよね~~~


       配列


その仕組みは簡単、簡単(^^)/


ふぅ ふふふふふふ


そして


ポインタ変数とはアドレスを格納する変数のことだった。


(前のエピソードでも見てきたようにポインタ変数に


ポインタ変数を代入して


ポインタ変数に格納されているアドレスを


ポインタ変数に渡すこともできるよ)

これも簡単だね。(^^)/


ふはは


ところで


まえから思っていたんだけど


先程の配列変数


hairetu[0]=1;

hairetu[1]=2;

hairetu[2]=3;


において


変数aを変数宣言後に


a=1;


と数値1が代入できたように


hairetu[0]に数値1が代入できるのなら


《《配列変数hairetu[0]って普通に変数なんじゃない?,


もしくは変数としての性質をもつ?》》


そう思わないかい? アレサ


そこで


配列変数hairetu[0]をふつうの変数とみなす。


すると


配列変数hairetu[0]に数値1が格納されているということは


配列変数hairetu[0]という名前の付いたメモリに数値1が格納されている


(または配列変数hairetu[0]がアクセスしているメモリに数値1が格納されている)


ということであり


もちろん


そのメモリにはアドレスがあることになる。


つまり


変数aに変数aのアドレス&aがあるように


配列変数hairetu[0]にも


配列変数hairetu[0]のアドレス&hairetu[0]があることになる。


そこで変数であろう配列変数hairetu[0]のアドレスである


&hairetu[0]がどのような値を持っているのかを


プログラムを組んで求めてみる。」


#include <stdio.h>


int main(void){


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

printf("%p\n",& hairetu[0]);


return 0;

}


コンパイル結果

0019FF4C


ソーラー「


数値1を格納しているhairetu[0]のアドレスは0019FF4C(*^^)v


あう、無事に求めることができた・・



おおウウウぉぉぉ   いいんじゃな~い



ねえ、アレサ


コンピュータが


hairetu[0]と&を組み合わせた


&hairetu[0]のアドレスを読み取れたとなると


やはり


配列変数hairetu[0]は


変数hairetu[0]としての性質をもっているみたいだね。


となると


pthairetu[0]をポインタ変数宣言することにより


作製されたポインタ変数pthairetu[0]に


配列変数hairetu[0]のアドレス&hairetu[0]を


格納することができるはずだよね。


ポインタ変数とは


変数のアドレスを格納するための変数だから


変数ともいえるhairetu[0]のアドレス&hairetu[0]を


格納することのできるポインタ変数


pthairetu[0]


を作ることができるのは普通のことだもんね💖」



さあ どうかな?


         solarplexussより


わおおぅ  いい流れじゃん・・・


さっそく


ポインタ変数pthairetu[0]をつくってhairetu[0]のアドレス、


&hairetu[0]を


ポインタ変数pthairetu[0]に格納してみよぅ

 

その手順は次のようになるね!


まず


配列宣言int hairetu[]={1,2,3};


によって


hairetu[0]に1を格納した後


配列変数hairetu[0]のアドレスを格納するためのポインタ変数


pthairetu[0]を


int *pthairetu[0];と


ポインタ変数宣言する


その後


作製された


ポインタ変数pthairetu[0]を初期化するために


配列変数hairetu[0]のアドレス&hairetu[0]を


pthairetu[0]=&hairetu[0];と


ポインタ変数pthairetu[0]に代入する。


後は


ポインタ変数pthairetu[0]に格納されているアドレスを


%p出力変換指定子をつかって16進数でprintf出力表示してみる。



それでは


その手順に沿ったプログラムを構成してみます


#include <stdio.h>


int main(void){


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


printf("%p\n",& hairetu[0]);/*ここで、まず hairetu[0]のアドレスを確かめています*/


int*pthairetu[0]; /*pthairetu[0]のポインタ変数宣言を行う*/


pthairetu[0]=&hairetu[0];/*ポインタ変数pthairetu[0]にhairetu[0]のアドレス&hairetu[0]を代入して初期化する*/


printf("%p\n", pthairetu[0]);/*ここで、ポインタ変数pthairetu[0]に

どのようなアドレスが格納されているか確認する*/

return 0;

}


ソーラー「まあ printf("%p\n", pthairetu[0]);


を行うと


ふつうに ポインタ変数pthairetu[0]に格納されている


hairetu[0]のアドレス&hairetu[0]が表示されるはずだよね。」



うちもそう思います

            solarplexussより



アレサ「ソーラーさん 、こういうの本当に お好きですね」


ソーラー「ははっ😊 マックスにもよくいわれるよ


それでは😊😊😊


              

             🍅コンパイルっ🍅 


  

コンパイル結果

EAZY IDECの場合


0019FF4C

0019FF4C


ビルド実行結果



エラー (アクティブ) E0094 配列のサイズは 0 より大きくなければなりません

エラー C2466 サイズが 0 の配列を割り当てまたは宣言しようとしました。

エラー C2133 'pthairetu': サイズが不明です。 9



ソーラー「Visual Studioのビルド結果はともかく


EAZY IDECのコンパイル結果をみてよ


(みなさんC++言語でお会いしましょう)


おおおおおぅぅぅ


やった・・・ふつうにやったよ


アレサ・・



おお娘やぁぁああああっ・・・


無事に


  配列変数hairetu[0]のアドレスがポインタ変数pthairetu[0]



に格納できているよ~。


おっお父さんは嬉しいよぉ~お~~~~


実はね アレサ


配列変数

hairetu[0]は


変数同様にあつかえるかどうか


わからない


だから&hairetu[0]はちゃんとポインタ変数pthairetu[0]に格納できるか


どうかな?


とおもっていたんだよ


⦅ 配列内のいれものの一つである配列変数hairetu[0]といっても ⦆


ようは、変数なんだから


そのアドレスは


ポインタ変数pthairetu[0]に格納できるというだけの話なんだね。


ふふふ~ん っていうかおわったかな?


これで説明?」


アレサ「ピンポ~ン、大正解です、ソーラーさん」


ソーラー「・・・ふふふ


最初は配列とポインタ変数の関係???


なんのことか


さっぱりだったんだけど…


なんかいがいと簡単におわったね😊」


アレサ 「 ソーラーさん すごく展開がはやいです 


ずんずんすすんでいくから」


ソーラー「しまったあ、娘さんやぁ 


わしゃあ・・・ボケるの忘れるとは・・・」


アレサ「正確には


ピンポ~ン、大正解です、 


              💖ここまでは💖


でよいのですよね?


ソーラーさん」


ソーラー「!!!!!!!!!」


アレサ 「もう、こんなにながい文章にわたって


うまいぐあいにボケをもってきましたのは


今までで はじめてではないですの?」


ソーラー「ぎくぅ・・・な、なんのこと」


アレサ「読者のみなさん 


今のトリックにお気付きになられましたか


ネタ明かしをいたします


今のプログラムには


ポインタ変数pthairetu[0]に間接参照演算子*を用いた


*pthairetu[0]を使用して


配列変数

hairetu[0]の中身に格納されている数値、


この場合は


その数値は1です。


をprintf出力表示する命令文


printf("%d\n", *pthairetu[0]);


はかかれていませんね。


とても基本的な命令文です」


ソーラー「ぎくぅ・・・」


アレサ

その命令文


printf("%d\n", *pthairetu[0]);を


実行すると1が出力されなければなりませんね😋」


ソーラー「😋😋もっと、もっとぉ😋😋もっと、もっとぉ」


アレサ「😋😋もっと、もっとですか・・・ひくっひくっひく・・


そこでこの命令文


printf("%d\n", *pthairetu[0]);


を先のプログラムに追加し


コンパイル結果をたしかめてみると


#include <stdio.h>


int main(void){


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


printf("%p\n",&hairetu[0]);/*ここで、まず hairetu[0]のアドレスを確かめる*/


int*pthairetu[0]; /*pthairetu[0]のポインタ変数宣言を行う*/


pthairetu[0]=&hairetu[0];/*ポインタ変数pthairetu[0]にhairetu[0]のアドレス&hairetu[0]を代入して初期化する*/


printf("%p\n", pthairetu[0]);/*ここで、pthairetu[0]にどのような数値、つまり、アドレスが格納されているか確認する*/


printf("%d\n", *pthairetu[0]);

/*😊追加された命令文はここです  

 いったい*pthairetu[0]にどのような数値が格納されているのでしょうか😊*/


return 0;

}



(EAZY IDECの場合)


コンパイル結果


0019FF4C (👈これはhairetu[0]のアドレスを表しています)

0019FF4C (👈これはpthairetu[0]に格納されているアドレスを表しています)

1703756 ( 👈これはアドレス&hairetu[0]のメモリに格納されている数値を表しています


(Visual Studioの場合)


エラー (アクティブ) E0094 配列のサイズは 0 より大きくなければなりません

エラー C2466 サイズが 0 の配列を割り当てまたは宣言しようとしました。

エラー C2133 'pthairetu': サイズが不明です。


(なぜVisual Studioでこのような表示が出てくるのかは


すぐに理解できるようになります


             solarplexussより」


アレサ「

この(EAZY IDECの場合)の


コンパイル結果の3行目がおかしいときづかれるはずです

 

ポインタ変数pthairetu[0]にhairetu[0]のアドレス&hairetu[0]を代入して


初期化したので


*pthairetu[0]には1が格納されているはずです


printf("%d\n", *pthairetu[0]);

を実行すると

アドレスhairetu[0]の場所に


格納されている数値1が出力されるはずですが・・・


1703756が表示されています


さらに


(Visual Studioの場合)ではビルドすらできません



このことは


🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋

🍋ポインタ変数                       🍋

🍋pthairetu[0]がhairetu[0]のポインタ変数として機能していない 🍋

🍋 🍋

🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋🍋 


ことをあらわしています。


原因は


もともと配列変数hairetu[0]が変数として完全には機能していないため


とおもわれますの ね、ソーラーさん」



太陽の光に 照らされに照らされ喜びだすソーラー


😋😋😋😋😋😋


ソーラー 「ぐごげぇぇぇぇぇぇぇぇぇ😋😋😋😋😋😋



  🌳pthairetu[0]はポインタ変数として機能している🌳 


がああああ😋😋😋😋😋😋


  🌳pthairetu[0]はポインタ変数として機能している🌳 


がああああ😋😋😋😋😋😋


シンプルに全否定されてしまったあぁぁぁぁぁぁぁ


おおおおおおおおおおおおおおおおおおおお


おおおおおおおおおお


もっと、もっと~~~😋😋😋」


アレサ 「つまりこのエピソードの冒頭で



         配列とポインタ変数の関係はなし



ソーラーさんの語った真の意味とは・・・」


ソーラー「はあ😋はあ😋はあ😋」


アレサ 「つまり


        

         配列とポインタ変数の関係はなし




ソーラーさんの語った真の意味とは・・・」



ソーラー「おぅぅぅおおおおおお、はあ、はあ」


地面に手をつきもがきだすソーラー。


アレサ 「配列変数hairetu[0]のアドレスを


ポインタ変数pthairetu[0]をつくり、


格納することはできても


*pthairetu[0]はhairetu[0]に格納されている


数値を表していない


すなわち


ソーラー「はあ、はあ、はああああああ,oo,oooooxtu」


アレサ「


😚配列変数hairetu[0]


にはうまく適応した


ポインタ変数を新たにつくることができない。😝


ということなのです。」


ソーラー「つくることができない。


そう


これで解決


配列とポインタ変数の関係は簡単でしたね。(^_-)-☆」



配列のポインタ変数については

まだまだお話はつづきます


                       solarplexussより


このプログラムで


配列変数


hairetu[0]のアドレスをポインタ変数pthairetu[0]


に格納してお話をすすめていました。


今度はhairetu[0]をhairetu[1]に変えて


配列変数


hairetu[1]のアドレスを


ポインタ変数pthairetu[1]を作成し


pthairetu[1]に格納してみます



すると・・・



#include <stdio.h>


int main(void){


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


printf("%p\n",&hairetu[1]);


int *pthairetu[1];


pthairetu[1]=&hairetu[1];


printf("%p\n", pthairetu[1]);


printf("%d\n", *pthairetu[1]);

/*😊追加された命令文はここです  

 いったい*pthairetu[1]にどのような数値が格納されているのでしょうか😊*/


return 0;

}


(EAZY IDECの場合)


コンパイル結果

0019FF50

0019FF50


(Visual Studioの場合)


ビルド実行結果


00BEF830

00BEF830

2


さらにおまけで


コマンドプロンプト画面とは


別の画面が表示されます。


画面には


program:

C:\Users\solarplexuss\source\repos\Project8\Debug\Project8.exe


module:

C:\Users\solarplexuss\source\repos\Project8\Debug\Project8.exe

File:


Debug Error!


Run-Time Check Failure#2-Stack around the variable 'pthairetu' was corrupted.


(Press Retry to debug the application)


と文章が表示され


さらに


中止  再試行  無視



の3つのボタンが表示されます


このエラー文はひとまずおいておきましょう。



なぜか 


hairetu[0]をhairetu[1]に変えただけの


同じプログラムなのに


きちんと,

*pthairetu[1]が機能し


printf("%d\n", *pthairetu[1]);

によって


hairetu[1]に格納されている数値2


が表示されています。


今度はhairetu[1]をhairetu[2]に変えて


プログラムをコンパイルしてみます。


#include <stdio.h>


int main(void){


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


printf("%p\n",&hairetu[2]);


int *pthairetu[2];


pthairetu[2]=&hairetu[2];


printf("%p\n", pthairetu[2]);


printf("%d\n", *pthairetu[2]);

/*😊追加された命令文はここです  

 いったい*pthairetu[2]にどのような数値が格納されているのでしょうか😊*/


return 0;

}



(EAZY IDECの場合)

コンパイル結果


0019FF54

0019FF54

3


(Visual Studioの場合)


ビルド実行結果


0075FEEC

0075FEEC


ここでも


さらにおまけで


コマンドプロンプト画面とは


別の画面が表示されます。


画面には


program:

C:\Users\solarplexuss\source\repos\Project8\Debug\Project8.exe


module:

C:\Users\solarplexuss\source\repos\Project8\Debug\Project8.exe

File:


Debug Error!


Run-Time Check Failure#2-Stack around the variable 'pthairetu' was corrupted.


(Press Retry to debug the application)


と文章が表示され


さらに


中止  再試行  無視



の3つのボタンが表示されます


このエラー文はひとまずおいておきましょう。


直ぐに後のエピソードで理解できるようになるでしょう。


このプログラムの実行結果でも


きちんと,


*pthairetu[2]が機能し


printf("%d\n", *pthairetu[2]);

によって


hairetu[2]に格納されている数値3


が表示されています。



よって


hairetu[0]のアドレスを格納した

pthairetu[0]のみが

うまくポインタ変数として機能していないのがわかります。





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

作者を応援しよう!

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

応援したユーザー

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