構造体配列のポインタにNULLを設定したいのですが、
よく分からないので教えてください。
開発OS :Windows95
開発ツール:VisualC++4.0(MFC不使用)
------------------------------------------
ある構造体の宣言
struct MyStructure
{
char c[5];
int n;
};
構造体のポインタを宣言しています。
struct MyStructure * p_MyStruct;
構造体10個分の領域を確保して、先頭アドレスをそのポインタに設定しています。
p_MyStruct = ( struct MyStructure *)malloc( sizeof( struct MyStructure ) *
10 );
/**************************************************/
ここでその構造体配列のメンバーに色々と代入なりの処理を行う。
/**************************************************/
ループで構造体配列を順番に全部見ていって
for( i=0;i<10;i++ )
{
構造体配列の中で、ある条件を満たすデータがあれば
if( p_MyStruct[i].n == 0)
{
そのデータのある構造体のポインタを NULLにしたい
p_MyStruct[i] = ( struct MyStructure * )NULL;
}
}
というような事を処理したいのですが、コンパイル時に以下のエラーとなります。
p_MyStruct[i] = ( struct MyStructure * )NULL;
→ error C2115: ’= ’ : 互換性のない型が含まれています。
ポインタ変数「p_MyStruct」は「struct MyStructure」 へのポインタですよね?
それが複数個あって、その中で条件に合う構造体のポインタに
ヌル(0)をセットしたいのですが・・・。
こういう代入の仕方は間違っているのでしょうか?
正しい方法を教えてくださいませんか?
よろしくお願いします。
> p_MyStruct[i] = ( struct MyStructure * )NULL;
p_MyStruct[i] はもはやポインタではないのですが、ポインタを正しく理解できていますか?
コンパイラが怒るのはあたりまえです。
どうすればよいかは、あなたが何がしたいのか良くわからないので答えられません。
C++ なんですよね。
構造体を malloc する癖は直ちに捨ててください。
> 構造体のポインタを宣言しています。
> struct MyStructure * p_MyStruct;
> 構造体10個分の領域を確保して、先頭アドレスをそのポインタに設定しています。
> p_MyStruct = ( struct MyStructure *)malloc( sizeof( struct MyStructure ) *
> 10 );
p_MyStructはたしかにstruct MyStructureへのポインタ型になります。
しかし,
> そのデータのある構造体のポインタを NULLにしたい
> p_MyStruct[i] = ( struct MyStructure * )NULL;
p_MyStruct[i]は,struct MyStructure型になります。直前に,
> if( p_MyStruct[i].n == 0)
とやっていますよね?
これは,p_MyStruct[i]がstruct MyStructure型だからできるのです。
> それが複数個あって、その中で条件に合う構造体のポインタに
> ヌル(0)をセットしたいのですが・・・。
> こういう代入の仕方は間違っているのでしょうか?
> 正しい方法を教えてくださいませんか?
まず,p_MyStructはstruct MyStructureへのポインタのポインタとして定義します。
struct MyStructure ** p_MyStruct ;
そして,要素それぞれにstruct MyStructure型のオブジェ
クトへのポインタを割り付けます。
p_MyStruct = malloc(sizeof(struct MyStructure *) * 10);
for (i = 0; i < 10; ++i) {
p_MyStruct[i] = malloc(sizeof(struct MyStructure));
}
このような構造になっていれば,p_MyStruct[i]はstruct MyStructure *型ですから,
空ポインタを割り付けることができます。
RESありがとうございます。
使用している言語は Cです。
環境は VC++4.0ですが、コードはすべてCです。
書き忘れていました、すいません。
-----------------------
ええ、うまく説明できなかったようです。
もう一度説明しますと、
構造体やポインタの宣言は済んでいるものとします。
1.ループで構造体の各メンバーに値を色々とセットしました
2.その後で、ある値がセットされたメンバーの構造体[N番目]を探して、
3.その構造体[N番目]のポインタにNULLをセットしておきたい・・・(参照するから)
それができたら、
別の処理で構造体[N]のポインタがNULLかどうか判定して、
それに応じて処理を変えたいのです。
だから、ああいう質問の仕方になってしまいました。
分かり難くてすいません。
グローバル変数や、新たなメンバーは追加したくありません。
この方法ではできないでしょうか?
構造体へのポインタ変数に NULL をセットしてしまったなら、
その変数を経由して元の(=目的の)構造体の実体にアクセスすることは不可能になりますが
それでもいいの?
# つーか、やっぱりやりたいことが良くわからない。
Yuoさん、RESありがとうございます。
ご指摘の方法でしか実現できないでしょうか?
というのは、どうしてもという場合以外はあまり
宣言や変数を追加したくないのです。
それによる、変更ボリュームが見えないので・・・。
わがままいってすいません。
ポインターと排列(はいれつ、配列)とが頭の中で整理できていないようです
> 構造体のポインタを宣言しています。
> struct MyStructure * p_MyStruct;
このポインターが示せるのは struct MyStructure 型の物がある番地(アドレス)です
ポインターですから NULL の場合もあります
> 構造体10個分の領域を確保して、先頭アドレスをそのポインタに設定しています。
> p_MyStruct = ( struct MyStructure *)malloc( sizeof( struct MyStructure ) *
10 );
と、正しく認識できているらしいのに
>p_MyStruct[i] = ( struct MyStructure * )NULL;
という不思議なコードが正しいものと思い込まれていることが私にはどういうことなのか分りま
せん
p_MyStruct が MyStructure 型の構造体10個分の配列の先頭番地でしたら、
p_MyStruct[i] は何だとお思いですか?
以上は最初の質問への疑問でした
> 3.その構造体[N番目]のポインタにNULLをセットしておきたい・・・(参照するから)
貴方が確保したのは構造体のポインターの排列ではなく、構造体の排列なのですから何番目で
あっても排列中には構造体 MyStructure へのポインターは有り得ません
多分、いわれているようなことは不可能でしょう。
話の様子だと、p_MyStructの型を変えてしまうと変更があちこちに波及するから
そのようなことをいっているのだと思いますが、このコードで大丈夫だろうという
判断をしている時点でポインタに関する理解が不十分であることは明白です。
まず、ポインタとは何かというところをもう一度勉強しなおされて方が良いでしょう。
どうしてもいいたいようなことをしたのであれば、YuOさんが言われているように
構造体のポインタの配列を作成しない限り無理であることに早く気づきましょう。
tetrapod さんへ
たびたびすいません。
目的が伝わらないのは、私の説明不足だと思うので補足します。
ある構造体Aがあります。
同じstruct型の構造体1、2があります。
これらは表と裏(メインとサブ)のような使い方をします。
構造体1、2は複数個の領域(例えば10個分×2種類)を確保&初期化しておきます。
これら構造体へのポインタはグローバルスコープを持ちます。
構造体Aの実体は一個だけ存在して、
ループ処理で、あるテキストファイルから構造体Aのサイズ分の1データを読み込ませます。
次に、今構造体Aに格納されているメンバーの値が「何か」である場合は、
構造体Aのデータを構造体1の添字番目に格納します。
反対に、値が「何か」で無い場合は、構造体2の添字番目に格納します。
時には、A → 1に格納
時には、A → 2に格納するといった具合です。
それで、全部のデータ(例えば10件)を格納し終わったとします。
最後に、データが格納されなかった構造体には、初期値(0など)を代入します。
つまり、空データはないものする訳です。
そして別の処理で、構造体1のあるメンバー①を参照するのですが
もし、構造体2のあるメンバー①にデータがあれば、それを参照し
無いのなら、構造体1のメンバー①を参照するという感じですね。
ここで、構造体2にデータが無いという事を、判定する為に
前述の初期値設定のところで、この構造体2の[N番目]にNULLを設定したかったのです。
ここでNULLを設定した、構造体2の[N番目]から実体を参照する事はありません。
その時は、構造体1の[N番目]のデータを参照したいので。
分かって頂けたでしょうか?
長々とすいません。
>>p_MyStruct[i] = ( struct MyStructure * )NULL;
>という不思議なコードが正しいものと思い込まれていることが
>私にはどういうことなのか分りません
>p_MyStruct が MyStructure 型の構造体10個分の配列の先頭番地でしたら、
>p_MyStruct[i] は何だとお思いですか?
島さんへ RESありがとうございます。
ええ、p_MyStruct[0]は構造体10個分の先頭番地だと思います。
p_MyStruct[1] となると、この構造体分アドレスが増加すると
思いましたので、次の構造体要素のアドレスを差すと思いました。
以下のようなイメージですね。
p_MyStruct[0] → 1個目の構造体の先頭アドレス
p_MyStruct[1] → 2個目の構造体の先頭アドレス
p_MyStruct[2] → 3個目の構造体の先頭アドレス
p_MyStruct[3] → 4個目の構造体の先頭アドレス
p_MyStruct[4] → 5個目の構造体の先頭アドレス
・
・
・
この辺が誤っていたようですね。
じゃあ、正しい理解とはどういうものですか?
>ええ、p_MyStruct[0]は構造体10個分の先頭番地だと思います。
これ自体間違っていますね?。
先頭番地ではなくて、先頭の要素(構造体一個まるまま)そのものでしょう?
番地を表すとしたら
&(p_MyStruct[0]) が先頭番地なんじゃないでしょうか?(先頭の要素の番地ですから)
島さんへ
指摘ありがとうございます。
おっしゃる通りです。
普通の配列と同じように考えれば、そうですよね。
では、この条件下でやりたい事を実現するには
判別用のメンバー変数を追加するか、
もしくは、今のメンバーに実際は取り得ない値を設定しておいて、
それを判定に使用するとかしかできなさそうですね。
とりあえず、それでやってみます。
ありがとうございました。
struct MyStructure * p_MyStruct =
(struct MyStructure *)malloc(sizeof(struct MyStructure) * 10);
MyStructure* apMyStr[10];
int nPos;
for (nPos = 0; nPos < 10; nPos++) {
p_MyStruct[nPos].n = 10000 + nPos;
apMyStr[nPos] = &p_MyStruct[nPos];
}
p_MyStructの領域はアドレスを保持する領域が1つ(4バイト)しかない
このアドレスはmalloc()で確保した領域の先頭を指している
p_MyStructが指している領域はMyStructureが10要素連続している領域である
MyStructure本体であって、ポインタではない
apMyStrの領域はアドレスを保持する領域が10個(4x10バイト)ある
forが全て終了すると、その10個のポインタ変数それぞれに
p_MyStruct[0]~p_MyStruct[9]のアドレスが保存される
それをしたかったらこうしなきゃあかん
struct MyStructure** pMyStruct = malloc( sizeof (struct MyStructure*) * 10 );
for( i =0; i<10 ; i++){
pMyStruct[i] = malloc( sizeof(struct MyStructure*) );
}
ああ失礼。入れ違い。