アプリ版:「スタンプのみでお礼する」機能のリリースについて

typedef struct _test_t{
int aaa;
int bbb;
} test_t;

typedef struct _globalData{
int xxx;
test_t* pTestData[256];
} globalData_t;

globalData_t globalData;


int main(){

test_t testData1 = {1,1};
test_t testData2 = {2,2};

*globalData.pTestData[1] = testData1; /* (1) */

globalData.pTestData[2] = &testData1; /* (2) */

}

上記のようなグローバルデータの構造体globalData
のメンバの構造体配列にtest_t型の構造体を格納し保持するには、
(1)、(2)のどちらが正しいでしょうか?

A 回答 (4件)

> 代入、*globalData.pTestData[xxx] = testData1;


> 削除 *globalData.pTestData[xxx] = NULL;

削除時点でヌルポインタになってしまうので、ご所望の書き方では削除後に代入はできません。
ちなみに削除はアスタリスクを取って
globalData.pTestData[xxx] = NULL;
が正しいと思います。

なぜNULLを代入したいのでしょうか?
「もしNULLなら構造体の値を代入」などの処理をしたいのであれば、まずはNULLのポインタに
領域を確保するか、すでに確保されているアドレスを代入することになります。
ご所望の代入方法をするためには、まず「領域の確保」が必要です。

これを踏まえて、代入と削除を書くと以下のようになるかと思います。

#include <stdio.h>
#include <string.h>

typedef struct _test_t {
int aaa;
int bbb;
} test_t;

typedef struct _globalData {
int xxx;
test_t *pTestData[256];
} globalData_t;

globalData_t globalData;

int main()
{
test_t testData1 = { 1, 1 };
test_t testData2 = { 2, 2 };

test_t testDataBuf[256];
int i;
for(i=0; i<256; i++)
globalData.pTestData[i] = &testDataBuf[i];

// 代入
*globalData.pTestData[1] = testData1;/* (1) */

// delete
globalData.pTestData[1] = NULL;

// 再代入
globalData.pTestData[1] = &testDataBuf[1]; // NULL状態を解消
*globalData.pTestData[1] = testData1;
}


しかし、これは無駄な処理に見えます。
このコードを読んだ人は「なぜDeleteがNULL代入なのだろうか?」と疑問に思うかもしれません。


私ならば・・・

案1
aaaが-1なら未使用というルールにして
#define delete_test_t(x) (x.aaa = -1)
#define is_enable(x) (x.aaa != -1)
とかで管理しといて、あとでソース読むのが楽になるようにケアすると思います。

案2
DeleteでNull代入する代わりにtest_t構造体に使用中フラグを追加


alloc禁止の前提ではこんなところですかね。
    • good
    • 0

> 構造体globalDataのメンバの構造体配列にtest_t型の構造体を格納し保持する



をどんな意味で使っているか、によって「正解」が変わります。

(1)は ポインタ globalData.pTestData[1] が示す実体(test_t構造体)に、testData1の内容をコピーする
(2)は ポインタ globalData.pTestData[2] の値を testData1のアドレスにする。
の意味です。

○ testData1のアドレスを覚えさせたい。
testData1.aaa=5 としたら、 global.pTestData[n].aaaも5になるようにしたい。
→ (2)のような形が正解

○ 現時点でのtestData1の中身を覚えさせたい。(コピーを保存しておきたい)
後に testData1.aaa=5 としても、 global.pTestData[n].aaaは記憶させた時点の1のままになるようにしたい。
→ 形は (1)が正解だが、今のままだとpTestData[2]が示す先にが入るべき領域が確保されていないので、期待通りに動かない。

この回答への補足

丁寧な回答ありがとうございます。

>○現時点でのtestData1の中身を覚えさせたい。(コピーを保存しておきたい)

グローバルデータに現時点でのtestData1の中身を保存しておきたく、
(1)のように実体を保存しようと思いました。


できれば配列を初期化時などに実体を一括して確保しておく方法はないでしょうか?
javascript:void(0);
ポインタ型の構造体メンバでは不可能でしょうか?

よろしくお願い致します。

補足日時:2012/06/06 07:58
    • good
    • 0

この例では(2)が正しいです。


(1)ではpTestData[1]が指すアドレスが不定な値にもかからわず、
その領域にtestData1の値を書き込もうとしています。

以下のようにすればどちらでも通ります。

typedef struct _test_t{
int aaa;
int bbb;
} test_t;

typedef struct _globalData{
int xxx;
test_t* pTestData[256];
} globalData_t;

globalData_t globalData;

int main()
{
test_t testData1 = {1,1};
test_t testData2 = {2,2};

globalData.pTestData[1] = malloc(sizeof(test_t));

*globalData.pTestData[1] = testData1; /* (1) */
globalData.pTestData[2] = &testData2; /* (2) */

// check
printf("%d\n", globalData.pTestData[1]->aaa);
printf("%d\n", globalData.pTestData[2]->aaa);
}

この回答への補足

サンプルコードまでつけていただきまして、ありがとうございます。

申し訳ありませんが、もうひとつ質問させてください。

グローバルの構造体のポインタメンバに値を格納する場合
>(1)ではpTestData[1]が指すアドレスが不定な値にもかからわず、
>その領域にtestData1の値を書き込もうとしています。

は理解しました。


他の複数の関数でも、同じようにグローバルデータに値を
代入、*globalData.pTestData[xxx] = testData1;
削除 *globalData.pTestData[xxx] = NULL;

をしようとしています。

できれば、malloc,freeによる動的確保、解放をおこなわず、
一括して領域を確保しておく方法はないでしょうか?

補足日時:2012/06/06 08:08
    • good
    • 0

実行してみました?



>*globalData.pTestData[1] = testData1;

globalData.pTestData[1]のポインタが指す先にtestData1をコピーする。
となり、

>globalData.pTestData[2] = &testData1;

globalData.pTestData[2]にtestData1のアドレスを格納する。
となります。

さて、(1)の時にglobalData.pTestData[1]のポインタは「中身を格納できる領域」を指していますか??
# コードとして掲示されていないけど、「どこか必要な場所を指している」のであれば問題ないでしょうが。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!