配列へのアドレス演算子、間接演算子について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sys

配列へのアドレス演算子、間接演算子について

#1

投稿記事 by sys » 14年前

2次元配列へのアドレス演算子と間接参照演算子についての質問です。(環境 xcode 3.2.5 64bit)

コード:

int main(void) {
  char array[2][3] = { "ab", "cd" };
  printf("&array → [%p] \n", &array);
  printf("&array+1 → [%p]\n", &array+1);
  printf("&*array → [%p] \n", &*array);
  printf("&*array+1 → [%p]\n", &*array+1);
  printf("&**array → [%p] \n", &**array);
  printf("&**array+1 → [%p]\n", &**array+1);
  return 0;
}
実行結果
&array → [0x7fff5fbff720]
&array+1 → [0x7fff5fbff726]
&*array → [0x7fff5fbff720]
&*array+1 → [0x7fff5fbff723]
&**array → [0x7fff5fbff720]
&**array+1 → [0x7fff5fbff721]

実行結果から
&array 配列(array[2][3])の最初の要素(a)へのポインタ 型:配列(array[2][3])へのポインタ
&*array 配列((*array)[3])の最初の要素(a)へのポインタ 型:配列((*array)[3])へのポインタ
&**array ポインタへのポインタが指す要素(a)のアドレス 型:ポインタへのポインタが指す要素(char)

&two_array+1 charの配列(要素数2)の配列(要素数3)を指しているので6加算
&*two_array+1 charの配列(要素数3)を指しているので3加算
&**two_array+1 charを指しているので1加算
と考えました。

上記の考え方で間違っているところはありますか?
ご回答よろしくお願い致します。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 配列へのアドレス演算子、間接演算子について

#2

投稿記事 by softya(ソフト屋) » 14年前

C++では、typeidで型が調べられるので調べてみました。
いくつかパターンも追加してあります。注目はsizeof()でポインタ値が同じでも型が違う場合があるって事にご注意下さい。

コード:

#include "stdlib.h"
#include "stdio.h"
#include <iostream>

int main(void) {
  char array[2][3] = { "ab", "cd" };
  printf("array( %s ) → [%p] \n",  typeid(array).name(), array);
  printf("&array( %s ) → [%p] \n",  typeid(&array).name(), &array);
  printf("array+1( %s ) → [%p]\n",  typeid(array+1).name(), array+1);
  printf("&array+1( %s ) → [%p]\n",  typeid(&array+1).name(), &array+1);
  printf("&*array( %s ) → [%p] \n",  typeid(&*array).name(), &*array);
  printf("&*array+1( %s ) → [%p]\n",  typeid(&*array+1).name(), &*array+1);
  printf("&**array( %s ) → [%p] \n",  typeid(&**array).name(), &**array);
  printf("&**array+1( %s ) → [%p]\n",  typeid(&**array+1).name(), &**array+1);
  printf("*array( %s ) → [%p]\n",  typeid(*array).name(), *array);
  printf("*array+1( %s ) → [%p]\n",  typeid(*array+1).name(), *array+1);
  printf("sizeof( *array ) = %d\n", sizeof( *array ) );
  printf("sizeof( &**array ) = %d\n", sizeof( &**array) );
  printf("sizeof( array ) = %d\n", sizeof( array) );
  return 0;
}
Windows7 64bit VC++9 x64で実行。
array( char [2][3] ) → [00000000002BF794]
&array( char (* __ptr64)[2][3] ) → [00000000002BF794]
array+1( char (* __ptr64)[3] ) → [00000000002BF797]
&array+1( char (* __ptr64)[2][3] ) → [00000000002BF79A]
&*array( char (* __ptr64)[3] ) → [00000000002BF794]
&*array+1( char (* __ptr64)[3] ) → [00000000002BF797]
&**array( char * __ptr64 ) → [00000000002BF794]
&**array+1( char * __ptr64 ) → [00000000002BF795]
*array( char [3] ) → [00000000002BF794]
*array+1( char * __ptr64 ) → [00000000002BF795]
sizeof( *array ) = 3
sizeof( &**array ) = 8
sizeof( array ) = 6
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sys

Re: 配列へのアドレス演算子、間接演算子について

#3

投稿記事 by sys » 14年前

ご回答ありがとうございます。
C++だと typeid で型を調べられるのですね。
ただ当環境で試したところ、同じような動作にならず実際に試すことが出来ませんでした。。。

(* __ptr64) の部分が可読出来れば理解出来そうなのですが、
(* __ptr64) の部分はどのように読めばいいのでしょうか?
調べたら __ptr64 は64 bit OS のネイティブポインタと出てきたのですが、ネイティブポインタがどうゆうものかまでは明確な説明が見つかりませんでした。

もう一点、
*array( char [3] ) → [00000000002BF794]
*array+1( char * __ptr64 ) → [00000000002BF795]
は、なぜ違う型になるのかもわかりません。

ご教示お願い致します。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 配列へのアドレス演算子、間接演算子について

#4

投稿記事 by softya(ソフト屋) » 14年前

sys さんが書きました:ご回答ありがとうございます。
C++だと typeid で型を調べられるのですね。
ただ当環境で試したところ、同じような動作にならず実際に試すことが出来ませんでした。。。
gccの64bitコンパイル環境は作っていないので違うかも知れませんね。
gccの32bit環境(Windows)で実行してみました。
array( A2_A3_c ) → [0028FF30]
&array( PA2_A3_c ) → [0028FF30]
array+1( PA3_c ) → [0028FF33]
&array+1( PA2_A3_c ) → [0028FF36]
&*array( PA3_c ) → [0028FF30]
&*array+1( PA3_c ) → [0028FF33]
&**array( Pc ) → [0028FF30]
&**array+1( Pc ) → [0028FF31]
*array( A3_c ) → [0028FF30]
*array+1( Pc ) → [0028FF31]
sizeof( *array ) = 3
sizeof( &**array ) = 4
sizeof( array ) = 6
その時のソースコード。

コード:

#include "stdlib.h"
#include "stdio.h"
#include <iostream>
 
int main(void) {
  char array[2][3] = { "ab", "cd" };
  printf("array( %s ) → [%p] \n",  typeid(array).name(), (void*)array);
  printf("&array( %s ) → [%p] \n",  typeid(&array).name(), (void*)(&array));
  printf("array+1( %s ) → [%p]\n",  typeid(array+1).name(), (void*)(array+1));
  printf("&array+1( %s ) → [%p]\n",  typeid(&array+1).name(), (void*)(&array+1));
  printf("&*array( %s ) → [%p] \n",  typeid(&*array).name(), (void*)(&*array));
  printf("&*array+1( %s ) → [%p]\n",  typeid(&*array+1).name(), (void*)(&*array+1));
  printf("&**array( %s ) → [%p] \n",  typeid(&**array).name(), &**array);
  printf("&**array+1( %s ) → [%p]\n",  typeid(&**array+1).name(), &**array+1);
  printf("*array( %s ) → [%p]\n",  typeid(*array).name(), *array);
  printf("*array+1( %s ) → [%p]\n",  typeid(*array+1).name(), *array+1);
  printf("sizeof( *array ) = %d\n", sizeof( *array ) );
  printf("sizeof( &**array ) = %d\n", sizeof( &**array) );
  printf("sizeof( array ) = %d\n", sizeof( array) );
  int a;
  std::cin >> a;
  
  return 0;
}
sys さんが書きました: (* __ptr64) の部分が可読出来れば理解出来そうなのですが、
(* __ptr64) の部分はどのように読めばいいのでしょうか?
調べたら __ptr64 は64 bit OS のネイティブポインタと出てきたのですが、ネイティブポインタがどうゆうものかまでは明確な説明が見つかりませんでした。
まぁ、64bitのポインタだと思って頂ければOKです。
sys さんが書きました: もう一点、
*array( char [3] ) → [00000000002BF794]
*array+1( char * __ptr64 ) → [00000000002BF795]
は、なぜ違う型になるのかもわかりません。
ご教示お願い致します。
*arrayだと直接配列の構造にアクセするので、char[3]と解釈されますが*array+1だとポインタとして演算されるためだと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sys

Re: 配列へのアドレス演算子、間接演算子について

#5

投稿記事 by sys » 14年前

gccの64bitコンパイル環境は作っていないので違うかも知れませんね。
gccの32bit環境(Windows)で実行してみました。
なるほど。同じく array( A2_A3_c ) と表示されてました。
では、これは読めるように自分で勉強してみます。
*arrayだと直接配列の構造にアクセするので、char[3]と解釈されますが*array+1だとポインタとして演算されるためだと思います。
わかりました。自分でもいろいろ試して理解したいと思います。
まぁ、64bitのポインタだと思って頂ければOKです。
* __ptr64 を()でくくるかくくらないかの違いはどう考えればよいですか?

&array( char (* __ptr64)[2][3] ) 
&**array( char * __ptr64 )

上記2例を間接参照演算子をつけた形を()でくくった
(* __ptr64)
を、ポインタとして読んでみると、

前者の &array( char (* __ptr64)[2][3] ) の型は、
charの配列(要素数2)の配列(要素数3)へのポインタ
と読めるのですが、そうすると後者の
&**array( char * __ptr64 ) の読み方がわからなくなります。

もしも後者が()でくくってある 
&**array( char (* __ptr64) ) となっていたら、
charへのポインタ
と読めて理解出来るのですが、、、。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 配列へのアドレス演算子、間接演算子について

#6

投稿記事 by softya(ソフト屋) » 14年前

sys さんが書きました:* __ptr64 を()でくくるかくくらないかの違いはどう考えればよいですか?

&array( char (* __ptr64)[2][3] ) 
&**array( char * __ptr64 )

上記2例を間接参照演算子をつけた形を()でくくった
(* __ptr64)
を、ポインタとして読んでみると、

前者の &array( char (* __ptr64)[2][3] ) の型は、
charの配列(要素数2)の配列(要素数3)へのポインタ
と読めるのですが、そうすると後者の
&**array( char * __ptr64 ) の読み方がわからなくなります。

もしも後者が()でくくってある 
&**array( char (* __ptr64) ) となっていたら、
charへのポインタ
と読めて理解出来るのですが、、、。
カッコが省略されているだけだと思います。
なので、
&**array( char (* __ptr64) )
と考えてもらえば良いです。

ところで、
PA2_A3_c
ですが、
Pはポインタ
Aはarray=配列
2や3は 配列の大きさ
cはcharを意味するはずです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sys

Re: 配列へのアドレス演算子、間接演算子について

#7

投稿記事 by sys » 14年前

softya(ソフト屋) さんが書きました: カッコが省略されているだけだと思います。
char *pt → Pc
&**array → Pc
で確認出来ました!
typeid().name() をいろいろ試してみましたが、強力ですね。

少々蛇足となりますが、今趣味で独学でC言語を勉強してて環境的に周りに聞ける人がいないので困っていました。
書籍、サイト、検索では答えに辿りつけないことがあるので、的確なコメントを頂けて非常に助かります。

ありがとうございました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: 配列へのアドレス演算子、間接演算子について

#8

投稿記事 by softya(ソフト屋) » 14年前

sys さんが書きました:
softya(ソフト屋) さんが書きました: カッコが省略されているだけだと思います。
char *pt → Pc
&**array → Pc
で確認出来ました!
typeid().name() をいろいろ試してみましたが、強力ですね。

少々蛇足となりますが、今趣味で独学でC言語を勉強してて環境的に周りに聞ける人がいないので困っていました。
書籍、サイト、検索では答えに辿りつけないことがあるので、的確なコメントを頂けて非常に助かります。

ありがとうございました。
なかなかいいところに目をつけて勉強されていると思います。
職業プログラマでも、ポインタに関しては理解不十分な人がたくさんいますので一歩抜きん出ているぐらいです。
これからも頑張ってください。いつでもお気軽に質問してくださいね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

sys
記事: 27
登録日時: 14年前

Re: 配列へのアドレス演算子、間接演算子について

#9

投稿記事 by sys » 14年前

性格的に理解出来ないと先に進めないタイプでして、ポインタだけで1ヶ月くらい勉強してます、、、。
最近わかることが多くなってきて、楽しくなってきました。

ありがとうございます。
また利用させて頂きたいと思います。

閉鎖

“C言語何でも質問掲示板” へ戻る