【问题标题】:How to include a dynamic array INSIDE a struct in C?如何在 C 中的结构中包含动态数组?
【发布时间】:2011-01-04 21:09:35
【问题描述】:

我环顾四周,但无法找到解决这个问题的方法。 这是我的代码:

 #include <stdlib.h>

struct my_struct {
    int n;
    char s[]
};

int main()
{
    struct my_struct ms;
    ms.s = malloc(sizeof(char*)*50);
}

这是 gcc 给我的错误: 错误:灵活数组成员的使用无效

如果我在结构中声明 s 的声明为

,我可以编译它
char* s

这可能是一个更好的实现(指针算法比数组快,是吗?) 但我认为在 c 中声明了

char s[]

相同
char* s

【问题讨论】:

  • char s[]char *s 相同,只是在函数的参数列表中。

标签: c pointers arrays struct memory-management


【解决方案1】:

您现在编写它的方式,过去被称为“struct hack”,直到 C99 将其称为“灵活数组成员”。您收到错误(可能无论如何)的原因是它需要跟一个分号:

#include <stdlib.h>

struct my_struct {
    int n;
    char s[];
};

当你为此分配空间时,你想要分配结构体的大小加上你想要的数组空间量:

struct my_struct *s = malloc(sizeof(struct my_struct) + 50);

在这种情况下,灵活数组成员是一个 char 数组,并且 sizeof(char)==1,因此您不需要乘以它的大小,但就像任何其他 malloc 一样,如果它是一个其他类型的数组:

struct dyn_array { 
    int size;
    int data[];
};

struct dyn_array* my_array = malloc(sizeof(struct dyn_array) + 100 * sizeof(int));

编辑:这与将成员更改为指针给出了不同的结果。在这种情况下,您(通常)需要两个单独的分配,一个用于结构本身,一个用于指针指向的“额外”数据。使用灵活的数组成员,您可以在单个块中分配所有数据。

【讨论】:

  • C99 实际上允许这样做 - 呃!
  • 哇,我从来没有见过这个......这是否依赖于“灵活数组成员”作为结构中声明的最后一个字段?您是否被限制为每个结构只有一个“灵活数组成员”?
  • @vicatcu:是的,你的两个问题。如果有记忆,如果你嵌入了一个包含灵活数组成员的结构,它必须是外部结构中的最后一个成员,所以当它们全部放在一起时,灵活数组成员总是最后一项。
【解决方案2】:

你需要先决定你要做什么。


如果你想要一个结构体,里面有一个指向[独立]数组的指针,你必须将它声明为

struct my_struct { 
  int n; 
  char *s;
}; 

在这种情况下,您可以以任何您喜欢的方式创建实际的结构对象(例如自动变量)

struct my_struct ms;

然后为数组独立分配内存

ms.s = malloc(50 * sizeof *ms.s);  

其实一般不需要动态分配数组内存

struct my_struct ms;
char s[50];

ms.s = s;

这完全取决于您需要从这些对象中获得什么样的生命周期。如果您的结构是自动的,那么在大多数情况下,数组也是自动的。如果结构对象拥有数组内存,那么这样做根本没有意义。如果结构本身是动态的,那么数组通常也应该是动态的。

请注意,在这种情况下,您有两个独立的内存块:结构和数组。


一种完全不同的方法是使用“struct hack”习语。在这种情况下,数组成为结构的一个组成部分。两者都驻留在单个内存块中。在 C99 中,该结构将被声明为

struct my_struct { 
  int n; 
  char s[];
}; 

要创建一个对象,您必须动态分配整个对象

struct my_struct *ms = malloc(sizeof *ms + 50 * sizeof *ms->s);

在这种情况下,计算内存块的大小以容纳结构成员和运行时大小的尾随数组。

请注意,在这种情况下,您无法创建静态或自动对象等结构对象。最后具有灵活数组成员的结构只能在 C 中动态分配。


您关于指针算法比数组更快的假设是绝对不正确的。根据定义,数组通过指针算术工作,因此它们基本相同。此外,真正的数组(不衰减为指针)通常比指针对象快一点。指针值必须从内存中读取,而数组在内存中的位置是从数组对象本身“已知”(或“计算”)的。

【讨论】:

  • UV for sizeof *ms + 50 * sizeof *ms-&gt;s:更易于查看和维护。
【解决方案3】:

只允许在结构的末尾使用未指定大小的数组,并且仅在某些编译器中有效。它是一个非标准的编译器扩展。 (虽然我想我记得 C++0x 会允许这样做。)

虽然数组不会是从结构中单独分配的。所以你需要分配所有的my_struct,而不仅仅是数组部分。

我所做的只是给数组一个小但非零的大小。通常 4 个用于字符数组,2 个用于 wchar_t 数组以保持 32 位对齐。

然后,您可以在进行分配时将声明的数组大小考虑在内。我通常不认为斜率小于堆管理器在任何情况下工作的粒度。

另外,我认为您不应该在分配中使用 sizeof(char*)。

这就是我会做的。

struct my_struct {
    int nAllocated;
    char s[4]; // waste 32 bits to guarantee alignment and room for a null-terminator
};

int main()
{
    struct my_struct * pms;
    int cb = sizeof(*pms) + sizeof(pms->s[0])*50;
    pms = (struct my_struct*) malloc(cb);
    pms->nAllocated = (cb - sizoef(*pms) + sizeof(pms->s)) / sizeof(pms->s[0]);
}

【讨论】:

    【解决方案4】:

    数组将解析为指针,在这里您必须s 定义为char *s。该结构基本上是一个容器,并且必须(IIRC)是固定大小的,因此根本不可能在其中拥有一个动态大小的数组。反正你是malloc内存,这对你追求的东西没有任何影响。

    基本上你是说,s 将指示一个内存位置。请注意,您以后仍然可以使用 s[0] 之类的符号来访问它。

    【讨论】:

      【解决方案5】:

      指针运算比数组快,是吗?

      根本不是——它们实际上是一样的。数组在编译时转换为指针算法。

      char test[100];
      test[40] = 12;
      
      // translates to: (test now indicates the starting address of the array)
      *(test+40) = 12;
      

      【讨论】:

        【解决方案6】:

        如果你选择用它声明一个自动变量,我怀疑编译器不知道它需要为 s[] 分配多少空间。

        我同意 Ben 所说的,声明你的结构

        struct my_struct {
            int n;
            char s[1];
        };
        

        另外,为了澄清他关于存储的评论,声明char *s 不会将结构放入堆栈(因为它是动态分配的)并在堆中分配s,它会解释第一个@将数组的 987654324@ 字节作为指针,因此您不会对您认为的数据进行操作,并且可能会是致命的。

        重要的是要记住,尽管指针和数组的操作可能以相同的方式实现,但它们并不是一回事。

        【讨论】:

          【解决方案7】:

          将数组存储在c结构中的工作代码,以及如何在数组元素中存储值如果您有任何疑问,请发表评论,我会尽力澄清

          结构定义:

          struct process{
              int process_id;
              int tau;
              double alpha;
              int* process_time;
          };
          

          进程结构的内存分配:

           struct process* process_mem_aloc = (struct process*) malloc(temp_number_of_process * sizeof(struct process));
          

          循环遍历多个进程并为每个进程更新 process_time 动态数组

          int process_count = 0;
          int tick_count = 0;
          
          
          while(process_count < number_of_process){
          
          
            //Memory allocation for each array of the process, will be containting size equal to number_of_ticks: can hold any value
          
                  (process_mem_aloc + process_count)->process_time = (int*) malloc(number_of_ticks* sizeof(int));
          

          从文件中逐行读取数据,存储到 process_time 数组中,然后从存储的值中打印出来,下一个 while 循环在进程 while 循环内

                  while(tick_count < number_of_ticks){
          
                      fgets(line, LINE_LENGTH, file);
                      *((process_mem_aloc + process_count)->process_time + tick_count) = convertToInteger(line);;
                      printf("tick_count : %d , number_of_ticks %d\n",tick_count,*((process_mem_aloc + process_count)->process_time + tick_count));
                      tick_count++;
                  }
          
                  tick_count = 0;
          

          【讨论】:

            【解决方案8】:

            生成的代码将是相同的(数组和 ptr)。除了数组无法编译这一事实之外,

            顺便说一句 - 使用 c++ 并使用向量

            【讨论】:

            • 建议我使用 c++ 和向量绝不是建设性的建议。你可以直接说:聘请软件工程师为你编写程序
            • 生成的代码甚至不会完全一样。数组不是指针。将数组嵌入到结构中或从结构中指向数组是完全不同的两件事。
            • 是的,你是对的,它们并不相同。我想说的是,如果代码正在处理作为 foo * 或 foo [] 传递给它的东西,那么代码将是相同的。本质上没有性能差异
            • Tom,有些人不知道 STL、c++ vector 等。我试图发布一些开箱即用的东西。如果你觉得这没有帮助,我很抱歉。
            猜你喜欢
            • 1970-01-01
            • 2017-05-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-04-02
            • 1970-01-01
            • 2013-09-30
            相关资源
            最近更新 更多