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

このQ&Aのポイント
  • char型の配列を直接Fooにキャストして利用したいが、Foo構造体のdataにint型の配列として利用することはできるか
  • foo->data=new int**[2]としてしまうとbytData[8]が破壊されてしまうため、別の方法を模索している
  • foo->data = (int**)&bytData[8]の部分がうまくいかないので、そもそもこの方法は無理だと考えている
回答を見る
  • ベストアンサー

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

こんばんわ。 以下のような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 ; }

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

ポインタと配列の違いを、もういちどちゃんと勉強しなおした方がいいと思います。 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++ではこれでは問題になることがあります

TeijigoTeatime
質問者

お礼

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

その他の回答 (3)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.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 でそうなってるしここを変える必然性はないと思うので今でも大丈夫じゃないかな. ほぼ「メンバが隙間無く並んでいるか?」も大丈夫だとは思うけどこっちが成り立つ必然性はない.

TeijigoTeatime
質問者

お礼

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

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.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のような使い方です …

TeijigoTeatime
質問者

お礼

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

  • wormhole
  • ベストアンサー率28% (1622/5659)
回答No.1

不可能です。

TeijigoTeatime
質問者

お礼

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

関連するQ&A

  • 関数に配列を渡した場合にサイズが

    C言語初心者です。 以下のように関数に配列を渡した場合、サイズが変わってしまうのは何故でしょうか。 #include "stdafx.h" void fanc(char [3]); int _tmain(int argc, _TCHAR* argv[]) { char a[] = {'a','b','c'}; printf("%d\n",sizeof(a)); // aのサイズ 3 fanc(a); return 0; } void fanc(char b[]){ printf("%d\n",sizeof(b)); // bのサイズ 4 }

  • _TCHAR*での引数の読み込み

    VC++2010での、通常の #include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { return 0; } のウィザードを使って、arvg[1]やargv[2]に引数を与えて、本体内で通常のCで使う printf("%s\n", argv[1]); や fopen(argv[1], "r"); を使いたいのですが、引数の型が_TCHAR*になっているため文字がそのまま使えません。 int main(int argc, char *argv[]) で使えば問題なく使えるのですが、デフォルトのウィザードを使った時の使い方を知っておきたいのです。 御経験のある方、御教示お願い致します。

  • 解の個数の求め方

    1~500までの数字のうち、3と5で割り切れる数の個数を求める問題で, int _tmain(int argc, _TCHAR* argv[]) { int n=0; for(n=1;n<=500;n=n+1) if((n % 5)==0 && (n % 3)==0) printf("%d\n",n); return 0; } ここまでは出来たのですが、これだと解は出てきますが、個数ではないので、問題の趣旨と違いますよね; どうやればいいのか、だれか教えてくれませんか?

  • ポインタのポインタ

    #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char **argv){ int i; if(argc != 2) { fprintf(stderr, "Usage: %s vector\n\tEx: %s 11110000\n", argv[0], argv[0]); return 1; } for(i=0;i<8;i++){ if(**argv == '0'){ printf("%d\n",i); } else{ printf("A%d\n",i); } argv++; } return 0; } コンパイルして./a.exe 10010011などと入力しても A0 A1 Segmentation Faultとなります。 どうすれば、 A1 0 ・・・省略 for文で回した8回分、出力が可能になるのか教えてください。 初歩的な質問ですいません。

  • C言語のprintfで桁数をそろえる

    次ので桁数をそろえると書いてあったけどやってみたらできなかった。 コンパイラはMS visual c++バージョンはおそらく7.1.3019 #include "stdafx.h" int _tmain(int argc, _TCHAR* argv[]) { int a; scanf("%d",&a); printf("a=%3d\n",a); return 0; }

  • 実行ファイルのメモリ上のアドレスについて

    実行ファイルのメモリ上のアドレスを以下の様に 書いて確かめましたがこのやりかたであっていますか? (=exeファイルがメモリ上に読み込まれているアドレス) また、実際にアドレスが表示されるのですが、このアドレスをみて 実際のメモリ本体のどこにロードされているかを理解する 必要はあるでしょうか? カーネルのプログラミングをしているときは必要? int _tmain(int argc, _TCHAR* argv[]) { printf("%p\n",_tmain); return 0; }

  • 文字配列から数値への変換

    MicrosoftのVisual-Studio 2005を使っています。 C/C++については、ほぼ素人で、困っています。 下記のような簡単なソースで、 456 012 678 を表示するようにしたいのですが、できなくて困っています。 最初の 123 789 345 は下記のソースで表記できたのですが、どうすればよいの でしょう? 数値をわざと文字列で読み込んで、これを 数値に変換しているのでややこしいのかもしれませんが、 できればこれでやりたいので、申し訳ありませんが、教えていただ けないのでしょうか。よろしくお願いします。 #include "stdafx.h" #include "stdlib.h" char str[3][200] = { "123 456", "789 012", "345 678" }; int _tmain(int argc, _TCHAR* argv[]) { int a[10]; for (argc = 0; argc < 3; argc++){ a[argc] = atof(str[argc]); printf("%d\n", a[argc]); }; return 0; }

  • C言語のフローチャート

    昨日に引き続き失礼します。下記のプログラムを作成したのですがフローチャートは、どのように書けばいいのでしょうか? #include "stdafx.h" #include <stdio.h> int _tmain(int argc, _TCHAR* argv[]) { char ss[10] = "abcdefg"; char *ssp; ssp =ss; while (1){ if (*ssp ==0) break; printf("文字 *ssp=%c\n",*ssp); ++ssp;} int ary[10] = {1,2,3,4,5,6,7,8,9,10}; int *pt; pt = ary; while (1) { if (*pt == 10) break; printf("値 *pt=%d\n",*pt); ++pt;} return 0; }

  • ポインタについての質問など

    (1) プログラム引数を取る時の記述ですが…. (int argc, char *argv[]) (int argc, char **argv) 本によって記述がまちまちなんです. これらはどう違うのでしょうか? 特に後者の解釈の仕方がいまいち分からないので教えてください. 配列になってないように見えるのですが…. (2) 後者の記述(int argc, char **argv)で書かれたプログラムで ./program.exe okwave と引数を取ったとき,okwaveのoからeまでをfor文やwhile文でたどって何らかの処理をしたいのですが,どうすればいいのでしょうか? (3) ポインタには関係ありませんが,Windowsでncursesは使えないのでしょうか?

  • 非常に基本的なポインタの使い方

    非常に基本的なところだと思いますが、ポインタの理解がうまくなく意図どおりのプログラムが書けません。 何らか引数を渡して(とりあえず文字列"hogehoge"を渡す)、そのポインタaをtest関数に渡して、ちゃんと"hogehoge"が渡っていれば「pass」と出力する 意図なんですが、どうもうまくいっていないようです。 ----------------------------- int test(char* a) { if(a == "hogehoge"){ printf("pass\n"); }else{ printf("ng\n"); } return 0; } int main(int argc, char* argv[]) { char* a = argv[0]; // "hogehoge"を渡しているとします。 test(a); return 0; } ----------------------------- 何がおかしいのか理解ができず、困っています。 ちなみに char* a = argv[0]; の箇所を単純に char* a = "hogehoge"; とした場合はうまくいくので、余計に混乱しております。 どなたか、正解例をご教授いただけませんでしょうか。