【问题标题】:Dynamically allocate structure and array in it in C在C中动态分配结构和数组
【发布时间】:2012-01-22 07:26:49
【问题描述】:
  1. 如何动态分配struct Register 的数组,每个寄存器都有一个动态分配的struct Field 数组?
  2. 我将如何访问这些成员(我可以使用Register_A.FieldArray[23].High吗?)?
  3. 如何有效地初始化寄存器结构(假设寄存器结构数组很大)? (就像一个不花费任何计算的数据段)

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

【问题讨论】:

    标签: c arrays memory dynamic structure


    【解决方案1】:

    您将不得不知道 FieldArray 有多大。如果不固定,则需要用最大值声明。然后你可以按照你的指定分配一个注册和访问

    【讨论】:

      【解决方案2】:

      一种方法是改变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;
      }
      

      这是一个如何使用它的示例:

      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';
      

      请记住,此解决方案仅在 FieldArray 位于 struct 末尾时才有效。

      【讨论】:

        【解决方案3】:

        我强烈建议您不要使用 flex 数组,因为它们不过是杂物。您应该将其声明为 struct Field *malloc 并将其用作任何其他动态数组的大小。

        也就是说,malloc 的数组大小为 n_elem

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

        访问元素:

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

        对于初始化:in gcc, at least, 您可以像任何其他静态数组一样静态初始化数组部分。我不确定其他编译器如何处理它。


        为什么不鼓励使用 flex 数组:

        我会链接this post,但我不认为答案是完整的(大部分气馁是因为它只是 c-99),所以我会添加我的想法。
        他们是个例外。本质上,您声明数组的大小为零,并且每次都超出范围访问它,只是在您分配的范围内。您不能像任何其他结构一样使用具有灵活数组的结构,例如您不能使用灵活数组 sizeof。如果声明一个静态成员或它们的数组,则不能使用该数组成员,因为没有为它分配空间。

        在数组中使用它们的示例:

        #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);
        }
        

        输出:

        0x7fff59b67164
        0x7fff59b67164
        

        他们在同一个地址。如果您尝试写入数组成员,则会覆盖下一个对象。如果您尝试从中读取数据,则会从下一个对象中读取数据。根据填充,这甚至可能是填充中的无意义值。

        它们就像goto 语句,两者都可能有用,但更多时候是个坏主意。如果您不知道它们为何危险,则不应使用它们(在实际代码中;在测试程序中使用它们以了解如何正确使用它们以及如何引入它们并不是一个坏主意问题)。

        【讨论】:

        • +1 表示不鼓励使用 flex 数组(不用说这是错误的)
        • 为什么不鼓励使用 flex 数组?我认为在引擎盖下它与使用指针相同。无论如何都可以在这种情况下使用吗?
        • @alertjean:阅读the C99 Standard 中的第 6.7.2.1 节并得出自己的结论。
        • 可以使用,但我添加了一些关于为什么不应该使用的信息。
        • 如果您在数组本身中使用具有灵活数组的结构,则您使用了错误的数据结构。如果他们正确使用它,我不会阻止任何人使用它。你有什么建议作为替代方案?带有指针和 malloc 数组的结构?这比灵活的阵列更容易或更清洁吗?不是。
        【解决方案4】:

        灵活的数组成员是 C99 的一部分。

        1. 您可以按照您的想法分配具有灵活数组成员的strucmalloc(sizeof(struct Register) + sizeof(struct Field[n])),其中n 是您想要的大小。不要忘记初始化数组并跟踪n,最好将成员专门用于该目的
        2. 是的

        顺便说一句:上面的malloc 可能由于填充而浪费了一些字节,但通常不值得考虑确切的公式。最小的有一个最大值并使用offsetof

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-08-22
          • 1970-01-01
          • 1970-01-01
          • 2012-05-17
          • 2021-10-30
          • 2017-03-30
          相关资源
          最近更新 更多