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