简体   繁体   English

在C中动态分配结构和数组

[英]Dynamically allocate structure and array in it in C

  1. How will I dynamically allocate an array of struct Register with each register having a dynamically allocated array of struct Field ? 我将如何动态分配struct Register数组,而每个寄存器都有一个动态分配的struct Field数组?
  2. How will I access each of these members (Can I use Register_A.FieldArray[23].High ?)? 我将如何访问这些成员中的每一个(我可以使用Register_A.FieldArray[23].High吗?)?
  3. How will I initialize register structure efficiently(assuming that register struct array is a big one) ? 我将如何有效地初始化寄存器结构(假设寄存器结构数组很大)? (Like a data segment without spending any compute) (就像一个数据段,而无需花费任何计算)

     struct Field { char High; char Low; char Attribute; }; struct Register { unsigned int ResetValue; struct Field FieldArray[]; }; 

I strongly discourage you from using a flex array, because they're nothing but a kludge. 我强烈不鼓励您使用flex数组,因为它们不过是一种麻烦。 You should instead declare and use it as a struct Field * , malloc ing it to size like any other dynamic array. 而应该声明,并把它作为一个struct Field *malloc是荷兰国际集团,以规模像任何其他动态数组。

That said, to malloc with an array size of n_elem : 这就是说,对malloc与阵列大小n_elem

struct Register register = malloc(sizeof(*register) + n_elem * sizeof(*register->FieldArray));

To access the elements: 要访问元素:

char high = register->FieldArray[0].High;

For initialization: in gcc, at least, you can initialize the array part statically like any other static array. 对于初始化: 至少在gcc中,您可以像其他任何静态数组一样对数组部分进行静态初始化。 I'm not sure how other compilers handle it. 我不确定其他编译器如何处理它。


Why flex arrays are discouraged: 为什么不鼓励使用弹性数组:

I'll link this post , but I don't think the answer is complete (most of the discouragement is because it's c-99 only), so I'll add my thoughts. 我将链接此帖子 ,但我认为答案并不完整(大多数不鼓励是因为它仅适用于c-99),所以我将添加我的想法。
They are an exception. 他们是一个例外。 In essence, you're declaring the array to be of zero size and accessing it out of bounds every time, just to an extent you have allocated for. 本质上,您是在声明数组的大小为零,并且每次都超出您所分配的范围而对其进行访问。 You can't use a struct with a flexible array just like any other struct, eg you can't take the sizeof the flexible array. 您不能像其他任何结构一样将结构与弹性数组一起使用,例如,您不能采用弹性数组的sizeof If you declare a static one or an array of them, you can't use the array member because there's no space allocated for it. 如果声明一个静态数组或它们的一个数组,则不能使用该数组成员,因为没有为其分配空间。

Example of using them in an array: 在数组中使用它们的示例:

#include <stdio.h>

struct test {
        int val;
        int arr[];
};

int main() {
        struct test tarr[2];
        printf("%p\n%p\n", &tarr[0].arr[0], &tarr[1].val);
}

Output: 输出:

0x7fff59b67164
0x7fff59b67164

They are at the same address. 他们在同一个地址。 If you try to write to the array member, you overwrite the next object. 如果尝试写入数组成员,则将覆盖下一个对象。 If you try to read from it, you read data from the next object. 如果尝试从中读取数据,则会从下一个对象读取数据。 Depending on padding, this could even be a nonsense value from the padding. 根据填充,这甚至可能是来自填充的废话值。

They're like goto statements, both are potentially useful but more often a bad idea. 它们就像goto语句,两者都可能有用,但通常是一个坏主意。 If you don't know why they're dangerous, you shouldn't be using them (in real code; it's not a bad idea to play around with them in a test program to see how to use them correctly and how they can introduce problems). 如果您不知道为什么它们很危险,就不应该使用它们(在真实代码中;在测试程序中使用它们以了解如何正确使用它们以及如何引入它们不是坏主意。问题)。

A way to do it is by changing the size of the struct Register : 一种方法是通过更改struct Register的大小:

struct Register 
{
   unsigned int    ResetValue;
   struct Field    FieldArray[1];
};
struct Register *Register_Create()
{
    struct Register *reg = calloc(1, sizeof(struct Register) - sizeof(struct Field));
    // check for NULL pointer
    return reg;
}

struct Register *Register_SetSize(struct Register *reg, size_t size)
{
    // check for NULL
    reg = realloc(reg, sizeof(struct Register) + sizeof(struct Field) * (size - 1));
    // check for NULL
    return reg;
}

Here's an example on how to use this: 这是有关如何使用此示例:

struct Register *reg = Register_Create();
reg = Register_SetSize(register, 5);
// You now have space for 5 elements in reg->FieldArray
reg->FieldArray[3].High = 'B';

Keep in mind that this solution only works if FieldArray is placed at the end of the struct . 请记住,只有将FieldArray放在struct的末尾,此解决方案才有效。

You are going to have to know how big the FieldArray is. 您将必须知道FieldArray有多大。 If it isn't fixed, you need to declare with max value. 如果它不是固定的,则需要使用最大值声明。 Then you can just alloc a Register and access as you specified 然后,您可以按照您的指定分配一个注册并访问

Flexible array members are a part of C99. 柔性阵列成员是C99的一部分。

  1. you can allocate a struc with flexible array member just as you think you should: malloc(sizeof(struct Register) + sizeof(struct Field[n])) , where n is the size you want. 您可以按照自己的想法分配具有灵活数组成员的strucmalloc(sizeof(struct Register) + sizeof(struct Field[n])) ,其中n是您想要的大小。 Don't forget to initialize the array and to keep track of n , best by dedicating a member to that purpose 不要忘记初始化数组并跟踪n ,最好是通过为此目的指定一个成员
  2. yes

BTW: the malloc above may be wasting some bytes due to padding, but usually it is not worth thinking about the exact formula. 顺便说一句:上面的malloc可能由于填充而浪费了一些字节,但是通常不值得考虑确切的公式。 The minimal one has a max and uses offsetof . 最小的有一个最大值,并使用offsetof

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM