ポインタを使った構造体の使い方 – プログラミング – Home

ポインタを使った構造体の使い方
 
通知
すべてクリア

[解決済] ポインタを使った構造体の使い方

固定ページ 1 / 2

どる
 どる
(@どる)
ゲスト
結合: 14年前
投稿: 5
Topic starter  

【環境】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


引用未解決
トピックタグ
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

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


返信引用
ホウジョウウサギ
 ホウジョウウサギ
(@ホウジョウウサギ)
ゲスト
結合: 18年前
投稿: 73
 

たとえば,提示のコードだと,
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
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

構造体の中で実体でデータを定義した時に
どれだけのメモリ容量が必要になるのかとか
そんな話かなと言う気もしますが。

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

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

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


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

うわ、誤字が。

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


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

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

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

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


返信引用
どる
 どる
(@どる)
ゲスト
結合: 14年前
投稿: 5
Topic starter  

回答いただきありがとうございました。

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

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

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

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

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


返信引用
どる
 どる
(@どる)
ゲスト
結合: 14年前
投稿: 5
Topic starter  

立て続けにすいません、
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
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

> 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)のコピーは注意が必要。
ポインタの指している実体をコピーするのか、ポインタをコピーするのかをちゃんと
意識してコピーする必要がある。
ここではどういうことをやりたいのか不明なのでどうすべきかはわからない。


返信引用
どる
 どる
(@どる)
ゲスト
結合: 14年前
投稿: 5
Topic starter  

maruさん
回答ありがとうございます。

単純に代入しても

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

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

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

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

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

分からない・・・


返信引用
ホウジョウウサギ
 ホウジョウウサギ
(@ホウジョウウサギ)
ゲスト
結合: 18年前
投稿: 73
 

正直,データ操作云々よりも前に 個人的には
本当にCStringを15000個も抱えたような構造体を必要としてるの!?
というあたりを見直すべきように思えるのですが,

とりあえず
> 何か間違っているみたいで落ちてしまいます・・・

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

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

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


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

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

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


返信引用
ryo
 ryo
(@ryo)
ゲスト
結合: 23年前
投稿: 252
 

同じ構造体をもとにたぶん同じ人?が質問してるので参考に

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

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


返信引用
maru
 maru
(@maru)
ゲスト
結合: 17年前
投稿: 358
 

しまった! pMagoはポインタだった。
代入するなら
*pMago[1] = *pMago[0];
ですね。


返信引用
PATIO
(@patio)
Famed Member
結合: 3年前
投稿: 2660
 

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

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

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


返信引用
固定ページ 1 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました