C 如何应用结构偏移?

C 如何应用结构偏移?,c,visual-c++,pointers,struct,pointer-arithmetic,C,Visual C++,Pointers,Struct,Pointer Arithmetic,我有一个结构 typedef struct foo { int lengthOfArray1; int lengthOfArray2; int* array1; int* array2; } foo; 我需要为整个结构及其数组的内容分配足够的内存。假设每个数组的长度为5 foo* bar = (foo*)malloc(sizeof(foo) + (sizeof(int) * 5) + (sizeof(int) * 5)); 现在,我必须将array1和arra

我有一个结构

typedef struct foo {
    int lengthOfArray1;
    int lengthOfArray2;
    int* array1;
    int* array2;
} foo;
我需要为整个结构及其数组的内容分配足够的内存。假设每个数组的长度为5

foo* bar = (foo*)malloc(sizeof(foo) + (sizeof(int) * 5) + (sizeof(int) * 5));
现在,我必须将array1和array2指向分配的缓冲区中的正确位置:

bar->array1 = (int*)(&bar->lengthOfArray2 + sizeof(int));
bar->array2 = (int*)(bar->array1 + lengthOfArray2);
这是正确的吗

编辑#1

为了澄清任何困惑:我试图将内存保存在一个块中,而不是三个块中

编辑#2


我不能使用C99,因为MSVC 2010编译器不支持它(http://stackoverflow.com/questions/6688895/does-microsoft-visual-studio-2010-supports-c99).

您必须分配结构的大小。然后,您必须分配具有各自大小的整数数组

foo* bar = malloc(sizeof(foo));

/* somewhere in here the array lengths are set then... */

bar->array1 = malloc(sizeof(int) * bar->lengthOfArray1);
bar->array2 = malloc(sizeof(int) * bar->lengthOfArray2);

具有少量额外内存(仅适用于C99):

#包括
#包括
typedef结构foo{
int lengthOfArray1;
int lengthOfArray2;
int*阵列1;
int*array2;
int数组[];
}傅;
内部主(空)
{
foo*bar=malloc(sizeof(foo)+(sizeof(int)*10);
条形->阵列1=&条形->阵列[0];
条形->阵列2=&条形->阵列[5];/*5或长度阵列1*/
返回0;
}

按照OP的方法,这应该可以完成工作:

/* Defining these types allows to change the types without having the need to modify the code. */
typedef int Foo_ArrayElement1_t;
typedef int Foo_ArrayElement2_t;

typedef struct Foo_s {
    size_t lengthOfArray1; /* 'size_t' is the type of choice for array/memory dimensions. */
    size_t lengthOfArray2;
    Foo_ArrayElement1_t * array1;
    Foo_ArrayElement2_t * array2;
} Foo_t;

/*
 * Allocates memory to hold a structure of type Foo_t including size for 
 * 's1' elements referenced by 'array1' and 's2' elements by 'array2'.
 * The arrays' elements are set to 0.
 *
 * Returns a pointer to the freshly allocated memory or NULL if the memory could not 
 * be allocated.
 */
Foo_t * Foo_CreateAndInit(size_t s1, size_t s2)
{
  /* At once allocate all 'Foo_t' (including the memory Foo_t's array pointers shall point to). */
  Foo_t * pfoo = calloc(1,
      sizeof(*pfoo) +
      s1 * sizeof(*(pfoo->array1) + 
      s2 * sizeof(*(pfoo->array2)));
  if (pfoo)
  {
    pfoo->lengthOfArray1 = s1;
    pfoo->lengthOfArray2 = s2;

    /* The first array starts right after foo. */
    pfoo->array1 = (Foo_ArrayElement1_t *) (pfoo + 1); 

    /* The second array starts right after s1 elements of where the first array starts. */
    pfoo->array2 = (Foo_ArrayElement2_t *) (pfoo->array1 + s1); /* That casting here is not 
        necessaryas long as 'Foo_t.array1' and 'Foo_t.array2' point to the same type but makes 
        the code work even if those types were changed to be different. */
  }

  return pfoo;
}

...

Foo_t * foo = Foo_CreateAndInit(5, 5);

这个答案的关键是有两个步骤,首先分配结构,然后分配结构指向的内存。你不能同时分配结构和数组内存,我个人觉得写:bar->arrayX=malloc(sizeof(*bar->arrayX)*bar->lengthOfArrayX)更好;如果您决定将类型从int更改为其他类型。生成相同的代码。按照您的方法创建三个独立的内存区域,这可能会使逻辑结构的处理(复制、清除)变得更加复杂,包括其动态数组成员。是的,我们可以…;-)@ChrisMansley@alk-在我回答之前,我查看了OPs之前的问题,21小时前他还不知道编译器可能会填充结构。我认为这个答案在这些情况下是恰当的,事实上,在99.9%的情况下也是如此?不,这是不正确的,只有最后一个成员可以使用灵活的数组(C99)以这种方式分配,请注意,这可以很好地一步完成。请参阅下面的某些答案@Davidrfy你可以通过使用
int-array[1]
并在
malloc
中减去1(使用灵活数组成员的“老”方法)来为任何编译器实现这一点。@nneonneo,是的,但正如c-faq所说,不清楚它是合法的还是可移植的,我查了大小,它似乎在C99中使用,但我无法使用。据我所知,
size\u t
早在
C99
之前就存在了。无论如何,数组大小至少不需要签名。因此,只需使用平台上
malloc()
/
calloc()
的参数所使用的类型即可@你打算做什么:sizeof(*pfoo)?或sizeof(Foo\u t)?
sizeof(*pfoo)
sizeof(Foo\u t)
返回相同的结果。第一个版本抵制
pfoo
声明中的更改,因为它简单地说:“告诉我我指的东西有多大,不管它是什么”。这种结构使代码的维护更加容易。因为更改
pfoo
的声明并不意味着需要更改分配代码。编译器不知道
int
s或
Foo\u t
之后会有任何其他内容@大卫杜夫
/* Defining these types allows to change the types without having the need to modify the code. */
typedef int Foo_ArrayElement1_t;
typedef int Foo_ArrayElement2_t;

typedef struct Foo_s {
    size_t lengthOfArray1; /* 'size_t' is the type of choice for array/memory dimensions. */
    size_t lengthOfArray2;
    Foo_ArrayElement1_t * array1;
    Foo_ArrayElement2_t * array2;
} Foo_t;

/*
 * Allocates memory to hold a structure of type Foo_t including size for 
 * 's1' elements referenced by 'array1' and 's2' elements by 'array2'.
 * The arrays' elements are set to 0.
 *
 * Returns a pointer to the freshly allocated memory or NULL if the memory could not 
 * be allocated.
 */
Foo_t * Foo_CreateAndInit(size_t s1, size_t s2)
{
  /* At once allocate all 'Foo_t' (including the memory Foo_t's array pointers shall point to). */
  Foo_t * pfoo = calloc(1,
      sizeof(*pfoo) +
      s1 * sizeof(*(pfoo->array1) + 
      s2 * sizeof(*(pfoo->array2)));
  if (pfoo)
  {
    pfoo->lengthOfArray1 = s1;
    pfoo->lengthOfArray2 = s2;

    /* The first array starts right after foo. */
    pfoo->array1 = (Foo_ArrayElement1_t *) (pfoo + 1); 

    /* The second array starts right after s1 elements of where the first array starts. */
    pfoo->array2 = (Foo_ArrayElement2_t *) (pfoo->array1 + s1); /* That casting here is not 
        necessaryas long as 'Foo_t.array1' and 'Foo_t.array2' point to the same type but makes 
        the code work even if those types were changed to be different. */
  }

  return pfoo;
}

...

Foo_t * foo = Foo_CreateAndInit(5, 5);