Arrays 结构数组的动态内存分配与静态内存分配

Arrays 结构数组的动态内存分配与静态内存分配,arrays,c,struct,calloc,Arrays,C,Struct,Calloc,如果您想分配一个struct数组,您可以通过声明 struct myStruct myStructArray[100]; struct myStruct *myStructArray = calloc(100, sizeof(struct myStruct) ); 或是和这样的人亲热 struct myStruct myStructArray[100]; struct myStruct *myStructArray = calloc(100, sizeof(struct myStruc

如果您想分配一个struct数组,您可以通过声明

struct myStruct myStructArray[100]; 
struct myStruct *myStructArray = calloc(100, sizeof(struct myStruct) );
或是和这样的人亲热

struct myStruct myStructArray[100]; 
struct myStruct *myStructArray = calloc(100, sizeof(struct myStruct) );
但在这种情况下,您负责释放内存

在许多应用程序和示例中,我发现了一种混合方法:

struct wrapperStruct
{
    int myInt;
    struct myStruct myStructArray[1];
};
然后按如下方式执行分配

int n = 100;
size_t memory_size = sizeof(struct wrapperStruct) + (n - 1) * sizeof(struct myStruct);
struct wrapperStruct *wrapperStruct_p = calloc(1, memory_size);
因此(如果我理解正确的话),由于数组是结构的最后一个成员,并且结构的字段在内存中的位置相同,因此您正在“扩展”具有99个条目的单条目数组
myStructArray
。 这允许您安全地编写类似于
wrapperStruct\u p.myStructArray[44]
的内容,而不会导致缓冲区溢出,也不必创建动态分配的struct数组,然后在最后处理内存。因此,替代方法是:

struct wrapperStruct
{
    int myInt;
    struct myStruct *myStructArray;
};

struct wrapperStruct *wrapperStruct_p = calloc(1, sizeof(struct wrapperStruct) );
wrapperStruct_p.myStructArray = calloc(100, sizeof(struct myStruct) )
问题是当您尝试释放
wrapperStruct\p
变量时会发生什么

您是否导致内存泄漏

C内存管理是否能够理解struct数组由100个条目而不是1个条目组成

除了不必在结构中释放指针之外,第一种方法还有什么好处

问题是当您尝试释放包装结构时会发生什么 变量

您是否导致内存泄漏

很有可能,但不是必须的。内部动态数组的内存未被释放,但如果将指针地址保存到其他变量,以后仍可以释放内存

C内存管理是否能够理解struct数组由100个条目而不是1个条目组成

“C内存管理”负责堆栈和堆分配(后者使用,因此可能它不是真正的“C内存管理”),除了在汇编程序上提供语法糖之外,它没有做其他什么(不像Java或其他垃圾收集语言)

C本身并不关心某处有多少个条目以及您访问的内存的哪一部分(SEGFULTS是操作系统对内存访问冲突的响应)

第一种方法的好处是什么 释放结构内部的指针

如果“第一种方法”指的是堆栈分配的数组,那么这主要是因为您不需要分配任何东西,堆栈会为您分配(缺点是它保持在声明的范围内分配,并且您无法释放或增加数组空间)然后是恒定的分配速度和保证,无论操作系统响应如何,您都可以获得100个阵列项(许多实时应用程序需要最大的响应时间,因此堆分配可能会造成很大的减速,从而导致问题)

如果“第一种方法”是指使用包装器结构,那么我看不到除了您已经说明的好处之外的任何好处

我甚至建议您不要提倡/使用这种方法,因为这是一种非常令人困惑的技术,没有明显的好处(另外,它分配了1个空间,尽管它可能没有被使用,但这是一个细节)


主要目标是编写易于他人理解的代码。如今,机器和编译器可以在代码方面创造奇迹,因此除非您是编译器设计师、标准库开发人员或嵌入式系统的机器级程序员,您应该编写简单易懂的代码。

我要注意的一点是,使用
struct myStruct myStructArray[1]的方法
实际上是在伪造a,我不建议这样做(如果它是合法的话)。这部分回答了“C内存管理是否能够理解结构数组由100个条目而不是1个条目组成?”因为使用FAM可以清楚地表明它不仅仅是1个元素,元素的数量存储在其他地方。这是因为,在C中,内存管理器是程序员。要在现代C中正确使用声明灵活数组成员,请使用
[]
而不是
[1]
。(在GCC中,您可以使用它的扩展名
[0]
。这不应该在新代码中使用。)如果您使用
[1]
,编译器可能会假设数组只有一个元素,而不管您分配了多少,因此优化可以将类似
p->member[复杂表达式]
的表达式转换为
p->member[0]
,因为零是一个元素数组的索引的唯一定义值(因此它是一种有效的优化,可以避免计算表达式),这会破坏您的程序。@EricPostChil我一直认为这个表达式
struct myStruct*myStructArray
相当于
struct myStruct myStructArray[]
。我认为在这两种情况下,您最终都会得到一个未初始化的指针。因此,如果您需要使用
calloc
malloc
分配这两种内存,那么您的内存将在堆中。是否正确?@Bemipefe:将成员声明为
struct myStruct*myStructArray
将在结构中创建指针。要使用它,您需要为结构分配内存,为
struct myStruct
数据单独分配内存,并将指针设置为指向该内存。当一个成员被声明为
struct myStruct myStructArray[]
时,它告诉编译器,当为该结构分配空间时,它可能包含用于
struct myStruct
数据的额外空间,这些额外元素将从结构中
myStructArray
所在的位置开始。@EricPostischil Ok谢谢。因此,如果我理解正确,当您使用
[]
代替
*
时,数组存储在结构的相同区域中。我想知道如果声明一个变量,比如
struct wrapperStruct ws。在这种情况下,结构存储在堆栈中,堆栈应该扩展以存储数组。我想知道是否能达到极限。我的意思是我需要分配
struct wrapperStruct*ws吗