结构数组的动态与静态内存分配
Dinamically vs Static memory allocation for a struct array
如果你想分配一个结构数组,你可以通过声明类似
的方式静态地完成
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);
所以(如果我理解正确的话)因为数组是结构的最后一个成员并且结构的字段在内存中遵循相同的位置那么你正在“扩展”单个条目数组 myStructArray
99 个条目。
这允许您安全地编写类似 wrapperStruct_p.myStructArray[44]
的东西,而不会导致缓冲区溢出,也不必创建动态分配的结构数组,然后在最后处理内存处理。所以替代方法是:
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 内存管理是否能够理解结构数组由 100 个条目而不是 1 个条目组成?
除了不必释放结构内部的指针外,第一种方法还有什么好处?
The question is what happens when you try to free the wrapperStruct_p
variable ?
Are you causing a memory leak ?
很有可能,但没有必要。内部动态数组的内存不会被释放,但如果您将指针地址保存到其他变量,您仍然可以稍后释放它。
Is the C memory management able to understand that the array of struct is made of 100 entries and not 1 ?
“C 内存管理”负责堆栈和堆分配(后者使用 systemcalls,所以它可能不是真正的“C 内存管理”),除了提供语法外,它没有做太多其他事情汇编程序之上的糖(不像 Java 或其他垃圾收集语言)。
C 本身并不关心某处有多少条目以及您访问了内存的哪一部分(SEGFAULTS 是 OS 对内存访问违规的响应)
What are the benefits of the first approach apart from not having to
free the pointer inside the struct ?
如果“第一种方法”是指堆栈分配的数组,那么主要是您不需要分配任何东西,堆栈会为您完成(缺点是它在声明的范围内保持分配状态,而您无法释放或增加数组 space) 那么无论 OS 响应如何,恒定的分配速度和保证你将获得 100 个数组项(许多实时应用程序需要最大响应时间,因此堆分配可能是一个非常大的减速导致问题)。
如果您所说的“第一种方法”是指使用包装器结构,那么除了您已经说明的好处之外,我看不到任何其他好处。
我什至建议你不要 advocate/use 这种方法,因为它是一种非常令人困惑的技术,没有明显的好处(而且它分配了 1 space,即使它可能不是甚至使用过,但这是一个细节)
主要目标是编写其他人易于理解的代码。现在机器和编译器可以用代码创造奇迹,所以除非你是编译器设计者,否则标准库嵌入式系统的开发人员或机器级程序员,您应该编写简单易懂的代码。
如果你想分配一个结构数组,你可以通过声明类似
的方式静态地完成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);
所以(如果我理解正确的话)因为数组是结构的最后一个成员并且结构的字段在内存中遵循相同的位置那么你正在“扩展”单个条目数组 myStructArray
99 个条目。
这允许您安全地编写类似 wrapperStruct_p.myStructArray[44]
的东西,而不会导致缓冲区溢出,也不必创建动态分配的结构数组,然后在最后处理内存处理。所以替代方法是:
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 内存管理是否能够理解结构数组由 100 个条目而不是 1 个条目组成?
除了不必释放结构内部的指针外,第一种方法还有什么好处?
The question is what happens when you try to free the wrapperStruct_p variable ?
Are you causing a memory leak ?
很有可能,但没有必要。内部动态数组的内存不会被释放,但如果您将指针地址保存到其他变量,您仍然可以稍后释放它。
Is the C memory management able to understand that the array of struct is made of 100 entries and not 1 ?
“C 内存管理”负责堆栈和堆分配(后者使用 systemcalls,所以它可能不是真正的“C 内存管理”),除了提供语法外,它没有做太多其他事情汇编程序之上的糖(不像 Java 或其他垃圾收集语言)。
C 本身并不关心某处有多少条目以及您访问了内存的哪一部分(SEGFAULTS 是 OS 对内存访问违规的响应)
What are the benefits of the first approach apart from not having to free the pointer inside the struct ?
如果“第一种方法”是指堆栈分配的数组,那么主要是您不需要分配任何东西,堆栈会为您完成(缺点是它在声明的范围内保持分配状态,而您无法释放或增加数组 space) 那么无论 OS 响应如何,恒定的分配速度和保证你将获得 100 个数组项(许多实时应用程序需要最大响应时间,因此堆分配可能是一个非常大的减速导致问题)。
如果您所说的“第一种方法”是指使用包装器结构,那么除了您已经说明的好处之外,我看不到任何其他好处。
我什至建议你不要 advocate/use 这种方法,因为它是一种非常令人困惑的技术,没有明显的好处(而且它分配了 1 space,即使它可能不是甚至使用过,但这是一个细节)
主要目标是编写其他人易于理解的代码。现在机器和编译器可以用代码创造奇迹,所以除非你是编译器设计者,否则标准库嵌入式系统的开发人员或机器级程序员,您应该编写简单易懂的代码。