8

C 構造体を動的に割り当てたい:

typedef struct {
    short *offset;
    char *values;
} swc;

「オフセット」と「値」はどちらも配列であると想定されていますが、そのサイズは実行時まで不明です。

構造体と構造体の配列にメモリを動的に割り当てるにはどうすればよいですか?

4

13 に答える 13

11

C:

swc *s = malloc(sizeof *s); // assuming you're creating a single instance of swc
if (s)
{
  s->offset = malloc(sizeof *(s->offset) * number_of_offset_elements);
  s->values = malloc(sizeof *(s->values) * number_of_value_elements);
}

C++ の場合:

try
{
  swc *s = new swc;
  s->offset = new short[number_of_offset_elements];
  s->values = new char[number_of_value_elements];
}
catch(...)
{
   ...
}

C++ では、動的に割り当てられたバッファーではなく、ベクターを使用した方がよい場合があることに注意してください。

struct swc 
{
  std::vector<short> offset;
  std::vector<char> values;
};

swc *a = new swc;

質問: 値は、個々の文字の配列または文字列の配列であると想定されていますか? それは物事を少し変えるでしょう。

編集

考えれば考えるほど、C++ の回答に満足できなくなります。C++ でこの種のことを行う正しい方法 (ベクトルではなく動的に割り当てられたバッファーが必要であると仮定するとおそらく必要ないでしょう) は、構造体型内のコンストラクターの一部としてオフセットと値のメモリ割り当てを実行することです。構造体インスタンスが破棄されたときに、デストラクタにこれらの要素の割り当てを解除させます (deleteまたはスコープ外への移動によって)。

struct swc
{
  swc(size_t numOffset = SOME_DEFAULT_VALUE, 
      size_t numValues = SOME_OTHER_DEFAULT_VALUE)
  {
    m_offset = new short[numOffset];
    m_values = new char[numValues];
  }

  ~swc()
  {
    delete[] m_offset;
    delete[] m_values;
  }

  short *m_offset;
  char  *m_values;
};

void foo(void)
{
  swc *a = new swc(10,20); // m_offset and m_values allocated as 
                           // part of the constructor
  swc b;                   // uses default sizes for m_offset and m_values
  ...
  a->m_offset[0] = 1;
  a->m_values[0] = 'a';
  b.m_offset[0] = 2;
  b.m_values[0] = 'b';
  ...
  delete a; // handles freeing m_offset and m_values
            // b's members are deallocated when it goes out of scope
}
于 2009-12-30T14:33:22.007 に答える
5

C:

typedef struct
{
    short *offset;
    char  *values;
} swc;

/// Pre-Condition:  None
/// Post-Condition: On failure will return NULL.
///                 On Success a valid pointer is returned where
///                 offset[0-n) and values[0-n) are legally de-refrancable.
///                 Ownership of this memory is returned to the caller who
///                 is responsible for destroying it via destroy_swc()
swc *create_swc(unsigned int size)
{
    swc *data    = (swc*)  malloc(sizeof(swc));
    if (data)
    {
        data->offset = (short*)malloc(sizeof(short)*n);
        data->values = (char*) malloc(sizeof(char) *n);
    }
    if ((data != NULL) && (size != 0) && ((data->offset == NULL) || (data->values == NULL)))
    {
        // Partially created object is dangerous and of no use.
        destroy_swc(data);
        data = NULL;
    }
    return data;
}
void destroy_swc(swc* data)
{
    free(data->offset);
    free(data->values);
    free(data);
}

C++ の場合

struct swc
{
    std::vector<short>   offset;
    std::vector<char>    values;
    swc(unsigned int size)
        :offset(size)
        ,values(size)
    {}
};
于 2009-12-30T15:30:54.793 に答える
3

ここで多くの正解に追加する必要があることの 1 つは、最後のメンバーに可変サイズの配列を収容するためにオーバーサイズの構造にすることができるということです。 malloc

struct foo {
   short* offset;
   char values[0]
};

以降

struct *foo foo1 = malloc(sizeof(struct foo)+30); // takes advantage of sizeof(char)==1

values配列内に 30 個のオブジェクトのためのスペースを確保します。あなたはまだする必要があります

foo1->offsets = malloc(30*sizeof(short));

同じサイズの配列を使用する場合。

私は通常、これを実際に行うことはありませんが (構造を拡張する必要がある場合、メンテナンスは悪夢です)、キットのツールです。

[ここのコードはcです。c++ でmalloc's (またはより適切な使用と RAII イディオム)をキャストする必要があります]new

于 2009-12-30T14:41:39.630 に答える
2
swc* a = malloc(sizeof(*a));
a->offset = calloc(n, sizeof(*(a->offset)));
a->values = calloc(n, sizeof(*(a->values)));

c では void* をキャストしないでください... c++ ではキャストする必要があります。

于 2009-12-30T13:57:51.247 に答える
1

ほとんどの答えは正しいです。あなたが明示的に尋ねていないことを追加したいと思いますが、重要かもしれません.

C/C++ 配列は、それ自体のサイズをメモリに保存しません。したがって、コンパイル時に定義された値を必要offsetvaluesしない限り (その場合は、固定サイズの配列を使用する方が適切です)、両方の配列のサイズをstruct.

typedef struct tagswc {
    short  *offset;
    char   *values;
    // EDIT: Changed int to size_t, thanks Chris Lutz!
    size_t offset_count;
    size_t values_count; // You don't need this one if values is a C string.
} swc;

免責事項:私は間違っているかもしれません。たとえば、offsetすべてのインスタンスのすべての が同じサイズの場合、 のメンバーとしてではなく、グローバル メンバーとしてswc格納する方が適切です。とについても同じことが言えます。また、が C 文字列の場合、そのサイズを保存する必要はありませんが、画家のシュレミエルのような問題に注意してください。offset_countstructvaluesvalues_countvalues

于 2009-12-30T15:51:27.887 に答える
1

まだ誰も言及していないので、1 回の割り当てでこのメモリのチャンクを取得すると便利なことがあります。

swc* AllocSWC(int items)
{
    int size = sizeof(swc); // for the struct itself
    size += (items * sizeof(short)); // for the array of shorts
    size += (items * sizeof(char)); // for the array of chars
    swc* p = (swc*)malloc(size);
    memset(p, 0, size);
    p->offset = (short*)((char*)swc + sizeof(swc)); // array of shorts begins immediately after the struct
    p->values = (char*)((char*)swc + sizeof(swc) + items * sizeof(short)); // array of chars begins immediately after the array of shorts
    return p;
}

もちろん、これは読み取りと保守が少し難しくなります (特に、配列が最初に割り当てられた後に動的にサイズ変更する場合)。多くの場所で使用されている代替方法です。

于 2009-12-30T16:30:51.267 に答える
1

メモリを動的に割り当てるには、malloc 関数または calloc を使用します。Googleで検索して例を取得します。

The calloc function initializes allocated memory to zero.
于 2009-12-30T12:13:55.100 に答える
0

上記に加えて、以下のように割り当てられたメモリを解放することを追加したいと思います。

    typedef struct { 
    short *offset; 
    char *values; 
} swc;

swc* createStructure(int Count1, int Count2) { 
  swc *s1 = new swc(); 
  s1->offset = new short[Count1]; 
  s1->values = new char[Count2]; 
  return s1; 
} 

int _tmain(int argc, _TCHAR* argv[])
{
    swc *mystruct;
    mystruct = createStructure(11, 11);

    delete[] mystruct->offset;
    delete[] mystruct->values;
     delete mystruct;
    return 0;
}
于 2009-12-30T14:53:10.200 に答える
0

**場合**配列のサイズを変更しない場合は、 を 1 回呼び出すだけで済みmalloc()ます。

swc *new_swc (int m, int n) {
    swc *p;
    p = malloc (sizeof (*p) + m * sizeof (p->offset[0]) + n * sizeof (p->values[0]);
    p->offset = (short *) &p[1];
    p->values = (char *) &p->offset[m];
    return p;
}

その後、 を 1 回呼び出すだけで解放できますfree()

(一般に、考慮すべきアラインメントの考慮事項がありますが、short の配列の後に char の配列が続く場合は問題ありません。)

于 2009-12-30T16:52:05.860 に答える