導入編 2次元配列の配列変数のアドレスを格納しているポインタ変数はどのように表されるのでしょうか?


2次元配列の配列変数のアドレスを格納しているポインタ変数はどのように表されるのでしょうか?


そのことについて考察していきたいと思います


このエピソードはその導入編となっています


続きのエピソードも合わせてご覧くださいね(^_-)-☆💖




ソーラー「そこで


次は


2次元配列宣言

char a[2][4];

を実行したとき

生成される配列変数


a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]


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


aを用いてどのように表されるかを観察してみよう」


アレサ「


2次元配列宣言

char a[2][4];

を実行したとき

生成される配列変数


a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]


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


aをもちいてですか?」


ソーラー「まずは


文字列データ

"cat"

"hat"



2次元配列を使ってメモリに格納してみます


そのときのプログラムはこちらです

👇

#include <stdio.h>


int main() {


char a[2][4] = { "cat","hat" };


printf("%c\n", a[0][0]);

printf("%c\n", a[0][1]);

printf("%c\n", a[0][2]);

printf("%c\n", a[0][3]);

printf("%c\n", a[1][0]);

printf("%c\n", a[1][1]);

printf("%c\n", a[1][2]);

printf("%c\n", a[1][3]);

printf("%s\n", a[0]);

printf("%s\n", a[1]);

return 0;


}



ビルド実行結果


c

a

t

(空白)

h

a

t

(空白)

cat

hat



ソーラー「このプログラムでは


char a[2][4] = { "cat","hat" };


の実行により


配列変数

a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]


が生成され


配列変数

a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]



文字データ

'c'

'a'

't'

'\0'

'h'

'a'

't'

'\0'


a[0][0]='c';

a[0][1]='a';

a[0][2]='t';

a[0][3]='\0';

a[1][0]='h';

a[1][1]='a';

a[1][2]='t';

a[1][3]='\0';


と代入されています


配列変数

a[0][0]

a[0][1]

a[0][2]

a[0][3]


側に

{ "cat","hat" }


の左から1番目の文字列データ"cat"を構成している文字データ


'c'

'a'

't'

'\0'



配列変数

a[1][0]

a[1][1]

a[1][2]

a[1][3]

側には

{ "cat","hat" }


の左から2番目の文字列データ"hat"を構成している文字データ

'h'

'a'

't'

'\0'


が格納されることになります



char a[2][4] の


2により

a[0]

a[1]


が生成され


さらに


char a[2][4] の

4により


配列変数

a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]

が生成されているというわけです


これらの配列変数はchar型なので文字データを格納することができていますね


これらの配列変数


a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]


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


aを用いて表すと


どのように表されるかな❔(*´▽`*)/]」


アレサ「


a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]

のアドレスを格納しているポインタ変数をaを用いて表すなら


たとえば

a

a+1

a+2

a+3

a+4

a+5

a+6

a+7

のように表されるのではないですか?


もし そうであれば


a

a+1

a+2

a+3

a+4

a+5

a+6

a+7

アスタリスク演算子*を用いた


a*

(a+1)*

(a+2)*

(a+3)*

(a+4)*

(a+5)*

(a+6)*

(a+7)*



a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]

をあらわすことになり


printf("%c\n", *a);

printf("%c\n", *(a+1));

printf("%c\n", *(a+2));

printf("%c\n", *(a+3));

printf("%c\n", *(a+4));

printf("%c\n", *(a+5));

printf("%c\n", *(a+6));

printf("%c\n", *(a+7));


を実行すれば


  printf("%c\n", a[0][0]);

printf("%c\n", a[0][1]);

printf("%c\n", a[0][2]);

printf("%c\n", a[0][3]);

printf("%c\n", a[1][0]);

printf("%c\n", a[1][1]);

printf("%c\n", a[1][2]);

printf("%c\n", a[1][3]);


を実行したときと同じように


c

a

t

(空白)

h

a

t

(空白)

コマンドプロンプト画面に表示されることになるのではないですか?」


ソーラー「あはっ そうだね😊


早速 そのプログラムを実行してみたいと思います

👇


#include <stdio.h>


int main() {


char a[2][4] = { "cat","hat" };


printf("%c\n", *a);

printf("%c\n", *(a+1));

printf("%c\n", *(a+2));

printf("%c\n", *(a+3));

printf("%c\n", *(a+4));

printf("%c\n", *(a+5));

printf("%c\n", *(a+6));

printf("%c\n", *(a+7));

return 0;


}



ビルド実行結果


(空白)

.


ソーラー「!!


な、なんと・・・」


アレサ「??


まったく


文字データが表示されません( ^ω^)・・・


不思議ですの」


ソーラー「う~ん


僕も


何か文字が表示されると思ったんだけど


何も全く表示されないとはおもわなかったね」


アレサ「そうですね


char a[2][4] = { "cat","hat" };


が実行されたとき


aは


2次元配列a[2][4]


を代表するアドレスを格納しているポインタ変数(👈間違っています)


つまり


char a[2][4] = { "cat","hat" };


が実行されたときに生成される配列変数


a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]


の先頭の配列変数


a[0][0]のアドレスを格納しているポインタ変数となり(👈間違っています)


printf("%c\n", *a);


が実行されたなら


c


がコマンドプロンプト画面に表示されそうなものですが・・・」


ソーラー「そう、そうなんだ~


僕も最初😊


そう思ったんだけど


実は

a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]



a

を用いて


**a

*(*a+1)

*(*a+2)

*(*a+3)

**(a+1)

*(*(a+1)+1)

*(*(a+1)+2)

*(*(a+1)+3)


とあらわされます

(💖どうしてこうなるのかはのちのエピソードで解説されます お楽しみに💖)



アレサ「!!」


ソーラー「😊


ですので


printf("%c\n",**a);

printf("%c\n", *(*a+1));

printf("%c\n", *(*a+2));

printf("%c\n", *(*a+3));

printf("%c\n", **(a+1));

printf("%c\n", *(*(a+1)+1));

printf("%c\n", *(*(a+1)+2));

printf("%c\n", *(*(a+1)+3));

が実行されると


文字データ

'c'

'a'

't'

'\0'

'h'

'a'

't'

'\0'

コマンドプロンプト画面に表示されることになります」


そのプログラムはこちらです

👇

#include <stdio.h>


int main() {


char a[2][4] = { "cat","hat" };


printf("%c\n", **a);

printf("%c\n", *(*a + 1));

printf("%c\n", *(*a + 2));

printf("%c\n", *(*a + 3));

printf("%c\n", **(a + 1));

printf("%c\n", *(*(a + 1) + 1));

printf("%c\n", *(*(a + 1) + 2));

printf("%c\n", *(*(a + 1) + 3));

return 0;

}

ビルド実行結果

c

a

t

(空白)

h

a

t

(空白)


アレサ「Σ(・□・;)


a[0][0]は**a

a[0][1]は*(*a + 1)

a[0][2]は*(*a + 2)

a[0][3]は*(*a + 3)

a[1][0]は **(a + 1)

a[1][1]は*(*(a + 1) + 1)

a[1][2]は*(*(a + 1) + 2)

a[1][3]は*(*(a + 1) + 3)


で表されるのですね


ということは


a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]

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


**a

*(*a+1)

*(*a+2)

*(*a+3)

**(a+1)

*(*(a+1)+1)

*(*(a+1)+2)

*(*(a+1)+3)


から


アスタリスク演算子*を取り除いた


*a

(*a+1)

(*a+2)

(*a+3)

*(a+1)

(*(a+1)+1)

(*(a+1)+2)

(*(a+1)+3)


となり


逆に

a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]

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


*a

(*a+1)

(*a+2)

(*a+3)

*(a+1)

(*(a+1)+1)

(*(a+1)+2)

(*(a+1)+3)


アスタリスク演算子*を用いた


**a

*(*a+1)

*(*a+2)

*(*a+3)

**(a+1)

*(*(a+1)+1)

*(*(a+1)+2)

*(*(a+1)+3)

a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]


をあらわすことになるのですね」


ソーラー「そうなんだ


実は


aはポインタ変数で


*aもポインタ変数なんです


(💖このことはのちのエピソードで解説されます お楽しみに💖)」


アレサ「?


aもポインタ変数で


*aもポインタ変数なんですの?


(💖このことはのちのエピソードで解説されます お楽しみに💖)」


ソーラー「そうなんだよ


ポインタ演算とは


ポインタ変数に数値を足し合わせることでした😊


ですので


ポインタ変数aに1を足す


          a+1


もポインタ演算で


ポインタ変数*aに1を足す


          *a+1


もポインタ演算なんです


そして


*a

(*a+1)

(*a+2)

(*a+3)

*(a+1)

(*(a+1)+1)

(*(a+1)+2)

(*(a+1)+3)


ポインタ演算が行われていて


足し算が行われているわけではないんです


ポインタ演算は


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


を表しています



*aはa[0][0]のアドレスを格納しているポインタ変数ですが


ポインタ演算(*a+1)はa[0][0]の次の配列変数


a[0][1]のアドレスを格納しているポインタ変数となり


ポインタ演算(*a+2)はa[0][1]の次の配列変数


a[0][2]のアドレスを格納しているポインタ変数となり


ポインタ演算(*a+3)はa[0][2]の次の配列変数


a[0][3]のアドレスを格納しているポインタ変数となります



ここで


配列変数


a[0][3]


の次の配列変数


a[1][0]


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


(*a+4)


ではなく


*(a+1)


となります



*aと*(a+1)に御注目下さい


*aはa[0][0]のアドレスを格納しているポインタ変数


*(a+1)はa[1][0]のアドレスを格納しているポインタ変数


となっています


つまり


*aはa[0][0]のアドレスを格納しているポインタ変数ですが


ポインタ変数aに1をたす


      ポインタ演算(a+1)


にアスタリスク演算子*が用いられた


*(a+1)は


a[0][0]👈*aはa[0][0]のアドレスを格納しているポインタ変数です

a[0][1]

a[0][2]

a[0][3]

a[1][0]👈*(a+1)はa[1][0]のアドレスを格納しているポインタ変数です

a[1][1]

a[1][2]

a[1][3]

a[0][1]

a[0][2]

a[0][3]

を飛びこえて

a[1][0]のアドレスを格納しているポインタ変数


となります



*(a+1)はa[1][0]のアドレスを格納しているポインタ変数となりましたが


*(a+1)に1をたす*(a+1)+1はa[1][1]のアドレスを格納しているポインタ変数となります


*(a+1)に2をたす*(a+1)+2はa[1][2]のアドレスを格納しているポインタ変数となります


*(a+1)に3をたす*(a+1)+3はa[1][3]のアドレスを格納しているポインタ変数となります

                             」

アレサ「このように


2次元配列a[2][4]の配列変数のアドレスを格納しているポインタ変数をaを用いてあらわすことができるのですね」


ソーラー「

a[0][0]

a[0][1]

a[0][2]

a[0][3]

a[1][0]

a[1][1]

a[1][2]

a[1][3]

には

文字データ

'c'

'a'

't'

'\0'

'h'

'a'

't'

'\0'


が格納されています


文字データ

'c'

'a'

't'

'\0'


を格納している連続した4つの配列変数

a[0][0]

a[0][1]

a[0][2]

a[0][3]

の先頭の配列変数はa[0][0]ですね


a[0][0]のアドレスを格納しているポインタ変数は*a


ですが


%s出力変換指定子を用いた

printf("%s\n", *a);


が実行されると


cat


がコマンドプロンプト画面に表示されます


同様に


文字データ

'h'

'a'

't'

'\0'


を格納している4つの連続した配列変数

a[1][0]

a[1][1]

a[1][2]

a[1][3]

の先頭の配列変数はa[1][0]ですね


a[1][0]のアドレスを格納しているポインタ変数は*(a+1)


ですが


%s出力変換指定子を用いた

printf("%s\n", *a);


が実行されると


hat


がコマンドプロンプト画面に表示されます


そのプログラムはこちらです

👇


#include <stdio.h>


int main() {


char a[2][4] = { "cat","hat" };


printf("%s\n", *a);

printf("%s\n", *(a + 1));

return 0;

}

ビルド実行結果


cat

hat






        













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

作者を応援しよう!

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

応援したユーザー

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

新規登録で充実の読書を

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

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

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