ポインタを使った構造体の使い方

[戻る]
どる 2010/11/29(月) 12:37:55
【環境】WindowsXP VC++2005 MFC

教えてください><

typedef struct TTestata{
    CString str1;
    CString str2;
    CString str3;
}stTestData;

上記構造体を持つ、「親」「子」「孫」の入れ子になった
構造体を使いたいのですが、どう定義すれば良いのか分からなくて困っております><


親は上限100で、子は10000、孫は1000です。

また、親は上記構造のデータを2つ持ち、子は5つ、孫は1つ持つのですが、


typedef struct TMago{
    stTestData mdata1[1000];
}stMago;

typedef struct TKo{
    stTestData kdata1[10000];
    stTestData kdata2[10000];
    stTestData kdata3[10000];
    stTestData kdata4[10000];
    stTestData kdata5[10000];
    stMago    *pMago[10000];
}stKo;

typedef struct TOya{
    stTestData odata1[100];
    stTestData odata2[100];
    stKo      *pKo[100];
}stOya;

stOya m_stOya;


このような定義で良いでしょうか?
「良いか」という伺い方では回答のしようが無いかもしれませんが、
ある方から
「
各データ構造体は都度mallocしていくつもりで
上位は下位の構造体の先頭アドレスの配列を持つような
線形リストにすべきかと思います。
」
と言われましたが、よく分からず・・・。
その人に連絡が取れない状態で困っております><

どのように定義し、どういった形でmallocすれば良いでしょうか?

「勉強しろー」ですとか「その人に聞けー」といった事を思われるのは
重々承知しておりますが、時間が無くて焦っております><

どうか教えてくださいm(__)m

仲澤@失業者 2010/11/29(月) 13:37:26
さまざまなケースが想定できるので正解を回答できる人はいないでしょう。
まず、はっきりさせたいのは
 1.親は子の配列を保持するのか?。
 2.子と孫の関係も上と同じか?。
 3.子や孫の構造とstTestDataは別の構造なのか。それらの部分なのか。
等などわんさかと疑問がわきます。
この原因は、そもそも
 4.stTestDataとは何であるのかの定義が不明。
 5.そのメンバstr1〜str3の意味が不明。
であるためです。
当たり前ですが、意味のわからないデータ群の構造を定義することはできません。

ホウジョウウサギ 2010/11/29(月) 13:44:02
たとえば,提示のコードだと,
TOya型はメンバにstTestData型を200個
TKoは5万個
TMagoは1000個も持っている! わけですが,
これはやりたいことと合っていますか?

文面から想像されるものと提示コードとの間に大きな差があるように見えます.

>親は上記構造のデータを2つ持ち、子は5つ、孫は1つ持つのですが

という記述からは,なんとなくですが,本当は

struct TMago
{
  stTestData mdata;
};

struct TKo
{
  stTestData kdata[5];
  std::list< TMago > MagoList;
};

struct TOya
{
  stTestData odata[2];
  std::list< TKo > KoList;
};

のような形なのかな?と感じました.

PATIO 2010/11/29(月) 13:47:50
構造体の中で実体でデータを定義した時に
どれだけのメモリ容量が必要になるのかとか
そんな話かなと言う気もしますが。

10000個の配列を作成した時に殆どのケースで10000個近い
配列が埋まった状態になるのであれば、実体でとるのも
わかりますが、実際には100個も使わないという話なら
実態を取ると同時にメモリも確保されてしまう実体の配列で
作成するのはメモリの無駄遣いです。
ましてや1000個の配列が5個もあるとなると
無駄に確保されているメモリの量もかなりの分量になります。
使うかどうかも分からない、もしくは使う可能性が低いメモリを
大量に確保しっぱなしと言うのは効率が悪いと判断するのは
至極最もだと思いますよ。

メモリの利用効率を最もよくするには必要な分だけ確保し、
不要になったら開放するという事になりますが、
メモリの確保と開放を繰り返すのは結構なオーバーヘッドに
なりますから、実際にはある程度閾値を持って対応する事が
多いです。
性能的な問題がでないのであれば、固定の配列にするよりも
コレクションクラスを使った可変長配列にした方が利用効率も
よく、ある程度の性能も期待できると思います。
C++言語を使って開発するのですからその部分に制約がないなら
コレクションクラスの利用も考えて見て良いと思います。

話の全体像が見えていないのでポインタを使った線形リストを
使う事が条件であれば、そちらで考える必要があると思います。

PATIO 2010/11/29(月) 13:49:47
うわ、誤字が。

正)
実体を取ると同時にメモリも確保されてしまう実体の配列で
作成するのはメモリの無駄遣いです。
ましてや10000個の配列が5個もあるとなると

maru 2010/11/29(月) 13:53:40
> 「
> 各データ構造体は都度mallocしていくつもりで
> 上位は下位の構造体の先頭アドレスの配列を持つような
> 線形リストにすべきかと思います。
> 」
> と言われましたが、よく分からず・・・。
リスト構造という用語を聞いたことが無いでしょうか?
検索すればいろいろ出てきます。
例えば
http://www.geocities.jp/ky_webid/algorithm/010.html

>    stTestData mdata1[1000];
といった宣言は、宣言した時点で1000個の構造体をとってしまいますが、
この数は上限であるので、実際に必要な数は場合によって異なると考えます。
そこで、助言者は「都度mallocしていく」ことを進めているのだと思います。

リスト構造はプログラムを作成する上での基本的なデータ構造の一つなので
覚えておいて損はないでしょう。

どる 2010/11/29(月) 20:08:29
回答いただきありがとうございました。

定義はそのままにしてあります。

使い方として、
pMago[0]の内容をpMago[1]にコピーしたい場合は

memcpy(m_stOya.pKo[0]->pMago[1], m_stOya.pKo[0]->pMago[0], sizeof(TMago));

で出来ると思うのですが、何だかアドレスがコピーされてしまっているような気がする
のですが、間違っておりますでしょうか?

よろしくお願いいたしますm(__)m

どる 2010/11/29(月) 20:42:38
立て続けにすいません、
pMago、pKoのそれぞれ指定した分のメモリ確保は

例)それぞれ10個と20個分メモリ確保したい場合
for(int i = 0; i < 10; i++)
{
m_stOya.pKo[i] = new TOya;
}


とした後、

for(int i = 0; i < 10;i++)
{
for(int j = 0; j < 20; j++)
{
m_stOya.pKo[i]->pMago[j] = new TMago;
}
}

で良いでしょうか?

【Q2】
また、これを解放するには、
同じループ処理を今度は内側から
for(int i = 0; i < 10;i++)
{
for(int j = 0; j < 20; j++)
{
Delete m_stOya.pKo[i]->pMago[j];
}
}

for(int i = 0; i < 10; i++)
{
Delete m_stOya.pKo[i];
}

で良いでしょうか?


何か間違っているみたいで落ちてしまいます・・・。
どう見ればおかしな点が探せるのかすら分からず困っておりますm(__)m

maru 2010/11/29(月) 21:22:42
> pMago[0]の内容をpMago[1]にコピーしたい場合は
> 
> memcpy(m_stOya.pKo[0]->pMago[1], m_stOya.pKo[0]->pMago[0], sizeof(TMago));
> 
> で出来ると思うのですが、何だかアドレスがコピーされてしまっているような気がす> のですが、間違っておりますでしょうか?
駄目ですね。
TMagoにはstTestDataが含まれており、stTestDataにはCStringが含まれています。
CStringは文字列をポインタで管理している部分があり、memcpyを使うと、ポインタ
のコピーが発生し、実体を指す複数のポインタが生成されてしまい、正しく管理され
なくなってしまいます。
TMagoのコピーをするなら単純に代入で可。
pMago[1]=pMago[0];

でも内部にポインタを持っているオブジェクト(TKo, TOya)のコピーは注意が必要。
ポインタの指している実体をコピーするのか、ポインタをコピーするのかをちゃんと
意識してコピーする必要がある。
ここではどういうことをやりたいのか不明なのでどうすべきかはわからない。

どる 2010/11/29(月) 22:08:01
maruさん
回答ありがとうございます。

単純に代入しても

m_stOya.pKo[0]->pMago[0]->mdata[1].str1
と
m_stOya.pKo[1]->pMago[0]->mdata[1].str1

が同じ結果になってしまいます・・・。

どこかでアドレス代入してしまっているという事に
なるのでしょうか・・・?

って言われても分からないですよね(^^;)

分からない・・・

ホウジョウウサギ 2010/11/30(火) 09:37:53
正直,データ操作云々よりも前に 個人的には
本当にCStringを15000個も抱えたような構造体を必要としてるの!?
というあたりを見直すべきように思えるのですが,

とりあえず
> 何か間違っているみたいで落ちてしまいます・・・> どこかでアドレス代入してしまっているという事に
> なるのでしょうか・・・?
といった事柄については
ステップ実行で動作を追ってみればどうでしょうか.


> m_stOya.pKo[i] = new TOya;
は書き間違え?


> 単純に代入しても
> ...
とは何をどう代入したのでしょう?
pMago[]は TMago * 型配列なのだから
> pMago[1]=pMago[0];
のようなことを「単純に代入」と言っているならば
> アドレス代入してしまっているという事に
ことになりますよ.

maru 2010/11/30(火) 12:05:10
> m_stOya.pKo[0]->pMago[0]->mdata[1].str1
> と
> m_stOya.pKo[1]->pMago[0]->mdata[1].str1
> 
> が同じ結果になってしまいます・・・。
同じ結果になるっていっても、代入しているんだから同じ結果にならないほうが
おかしいわけで...
どんな結果を期待していたの?

intのような単純なデータ型ではmemcpyと代入の結果は同じだが、CStringのような
内部にスマートなポインタを持っているようなものではmemcpyと代入は別の結果に
なる。そのことをいってるんだけどな。

ryo 2010/11/30(火) 12:33:59
同じ構造体をもとにたぶん同じ人?が質問してるので参考に

http://questionbox.jp.msn.com/qa6352393.html

#追加質問がマルチポストにあたりそうだが・・・

maru 2010/11/30(火) 12:37:36
しまった! pMagoはポインタだった。
代入するなら
*pMago[1] = *pMago[0];
ですね。

PATIO 2010/11/30(火) 15:14:35
マルチポストしてしまっているのであれば、
書き込んだ先の全ての掲示板の後始末はちゃんとしてくださいね。
それぞれの掲示板に最終結果の報告が必要です。
マルチで書き込んだ以上はそれが責任と言うものです。

マルチポストが嫌われるのは後始末をきちんと出来ない人が多いからです。

マルチポストはしないが吉。
見ているメンツも大して変わりませんし。

仲澤@失業者 2010/11/30(火) 17:28:31
http://oshiete.goo.ne.jp/qa/6352393.html
これも似たような(笑)。

瀬戸っぷ [E-Mail] 2010/12/01(水) 01:31:55
OKWave提携なので、同じモノです。
質問No.が6352393ですから。

どる 2010/12/02(木) 16:21:41
[[解決]]
ご回答ありがとうございました。

*pMago[1] = *pMago[0];
で出来ました。

古いスレッドには追加発言できません。