こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

ポインタのアドレスについて

こんばんわ。
以下のようなchar型の配列を直接Fooにキャストして利用したいのですが、
Foo構造体のdataにはint型の配列として利用したいのですが可能でしょうか?
char型の配列を直接Fooにキャストした後にdataの部分を操作すれば
可能かと思っていたのですがうまくいきません。
foo->data=new int*[2];
としてしまうとbytData[8]が破壊されてしまいます。
このような方法は無理でしょうか?

struct Foo
{
   int   tenmp ;
   int   count ;
   int**  data ;
} ;

char bytData[ 4 + 4 + 8 ] = { 1, 0, 0, 0,
                2, 0, 0, 0,
                3, 0, 0, 0,
                4, 0, 0, 0,
} ;

int _tmain(int argc, _TCHAR* argv[])
{
   Foo*foo ;

   foo = reinterpret_cast< Foo* >( bytData ) ;

   foo->data = (int**)&bytData[ 8 ] ;// ここがダメ。

   printf( "%d\n", *foo->data[ 0 ] ) ;// 3
   printf( "%d\n", *foo->data[ 1 ] ) ;// 4

   return 0 ;
}

投稿日時 - 2015-01-21 18:44:09

QNo.8899287

困ってます

質問者が選んだベストアンサー

ポインタと配列の違いを、もういちどちゃんと勉強しなおした方がいいと思います。

foo = reinterpret_cast< Foo* >( bytData ) ;
の後では
 アドレスbyData : foo->tenmpの領域 : 値=0x00000001
 アドレスbyData+4 : foo->countの領域 : 値=0x00000002
 アドレスbyData+8 : foo->dataの領域 : 値=0x0000000400000003
となっています。
dataは int**ですから、 data[0] は 「dataの値が示すアドレスにある、 int *の値」 です。
 アドレス 0x0000000400000003 : foo->data[0]の領域: 仮に 0x1000000000000000 とする
*foo->data[ 0 ] とすれば、「上記のアドレスが示すアドレスにある、intの値」となります。
 アドレス 0x1000000000000000 : *foo->data[ 0 ]の領域: 仮に 0x000000010 とする
→ printf( "%d\n", *foo->data[ 0 ] ) ;// 0x000000010 = 16

foo->data=new int*[2]; では、 foo->dataの領域に、 new int*[2]の結果が代入されます。
new int*[2] で 0x2000000000000000 が確保されたとすると
 アドレスbyData+8 : foo->dataの領域 : 値=0x2000000000000000
よって
> bytData[8]が破壊されてしまいます
というのは当り前の現象です。


struct Foo
{
   int  tenmp ;
   int  count ;
   int  data[2] ;
} ;
と配列で宣言すると、dataとして int2個分の領域がFooの中に確保されます。

 アドレスbyData : foo->tenmpの領域 : 値=0x00000001
 アドレスbyData+4 : foo->countの領域 : 値=0x00000002
 アドレスbyData+8 : foo->data[0]の領域 : 値=00000003
 アドレスbyData+12 : foo->data[1]の領域 : 値=0x00000004
となる *** 可能性はあります ***
ですが
○sizeof(int)がいくつになるか?
○メンバがこの順番に並んでいるか?
○メンバが隙間無く並んでいるか?
○3,0,0,0 は 3なのか、0x03000000 なのか、それ以外なのか
といったことが、コンパイラ,CPU,OS,設定等によって違ってくることがあります。
精通している人が理解した上で、十分に注意して使う(でも使いたくない)裏技です。
// 特に、C++ではこれでは問題になることがあります

投稿日時 - 2015-01-21 22:50:19

お礼

早々のご返答ありがとうございます。
とても参考になます。改めて勉強不足を実感しました。
また環境を書いていませんでした。大変失礼しました。

投稿日時 - 2015-01-22 09:27:06

ANo.3

このQ&Aは役に立ちましたか?

16人が「このQ&Aが役に立った」と投票しています

回答(4)

ANo.4

いやいや, int が 4バイトかつ 4バイトアラインと仮定すれば
foo->data=new int*[2];
で「bytData[8]が破壊される」のは明らかでしょ? むしろ何をどう考えたら「破壊されない」と思えるのかが知りたいよ.

端的にいえば
int x = 1;
x = 2;
とやったときに「x が 1 のままでないのはおかしい」って思うか, ってことなんだけど....

ちなみに「メンバがこの順番に並んでいるか?」だけは (その場合) 規格で保証されているはずです>#3. 今の規格 (C++11 and/or C++14) を持っていないの「はず」としておくけど, C++98 でそうなってるしここを変える必然性はないと思うので今でも大丈夫じゃないかな. ほぼ「メンバが隙間無く並んでいるか?」も大丈夫だとは思うけどこっちが成り立つ必然性はない.

投稿日時 - 2015-01-22 02:02:59

お礼

早々のご返答ありがとうございます。
とても参考になり、改めて勉強不足を実感しました。
また環境を書いていませんでした。
お手数をおかけして申し訳ありません。

投稿日時 - 2015-01-22 09:26:07

ANo.2

やるとすれば Fooの定義を

struct Foo {
  int tenmp;
  int count;
  int* data[1];
};

といった具合に定義してやる方法だと思います

Foo* foo;
foo = einterpret_cast< Foo* >( bytData );

// これは不要
// foo->data = (int**)&bytData[ 8 ] ;// ここがダメ。
  printf( "%d\n", *foo->data[ 0 ] ) ;// 3
  printf( "%d\n", *foo->data[ 1 ] ) ;// 4


WinAPIで使う BITMAPINFOのような使い方です …

投稿日時 - 2015-01-21 22:13:40

お礼

早々のご返答ありがとうございます。
ビットマップを読み込んだことがありましたのでなるほどと思いました。

投稿日時 - 2015-01-22 09:27:50

ANo.1

不可能です。

投稿日時 - 2015-01-21 19:23:34

お礼

早々のご返答ありがとうございます。
他の方の意見も踏まえて無理だと判断しました。

投稿日時 - 2015-01-22 09:28:44

あなたにオススメの質問