C编程-栈和堆数组声明

4

假设我声明一个数组为 int myarray[5]

或者将其声明为 int*myarray=malloc(5*sizeof(int))


这两个声明是否设置了相等数量的内存(以字节为单位)? 不考虑前一个声明是用于堆栈,而后者是用于堆。

谢谢!


你也可以使用 int* myarray = new int [5] - Konstantin Schubert
1
从上面的注释可以看出,在C语言中没有关键字“new”。 - REMberry
4个回答

6

在使用myarray时,有一个基本的区别可能并不明显:

  • int myarray[5];声明了一个由五个整数组成的数组,该数组是自动变量(且未初始化)。

  • int *myarray = malloc(5 * sizeof(int));声明了一个指向整数的指针变量(也是自动变量),该指针被初始化为一个库调用的结果。该库调用承诺将导致所得到的指针指向一个足够大的存储五个连续整数的内存区域。

由于指针算术、数组指针衰减以及a[i]*(a+i)等价的约定,您可以像使用myarray[i]一样使用这两个变量。这当然是有意设计的。

如果您正在寻找区别,那么以下内容可能会有所帮助:五个整数数组是一个单一的对象,它具有确定的大小。相比之下,malloc库调用不会创建任何对象。它只是分配了足够的内存(并适当对齐),但它也可能分配更多的内存。

(在C++中,当然还有内存和对象之间的附加区别。)


我还想补充一点关于使用C++和指针的注意事项,特别是在声明期间仅修改指针值时,最好使用引用来避免不良行为。 - Ken

3

简短回答:通常情况下,后者使用比较少但更大的内存。

详细回答: 内存管理需要使用一些额外的内存来管理返回的指针,并能够跟踪它,在稍后的时间释放它,您需要声明一个额外的指针来指向该内存。所以它的实际内存大小是sizeof(int*) + malloc_overhead。但在第一种情况中,您恰好使用了5个int(加上对齐可能)。


3

两种方法都不能保证确切地分配 5*sizeof(int) 字节,但两种方法都至少给您提供了这么多的空间(假设没有分配失败或栈耗尽)。

在第一种情况下,堆栈变量可能被对齐填充和/或堆栈安全标识包围(具体取决于编译选项)。这可能导致堆栈指针调整超过 5*sizeof(int) 字节。

在第二种情况下,您在堆栈上分配了一个 int *sizeof(int *) 字节),加上 malloc 返回的空间。 malloc 可能会以分配跟踪结构、对齐填充、链表指针等形式分配额外的内存。因此,在这种情况下,您也不能保证确切地分配 5*sizeof(int) 字节。

如果您想非常精确地使用内存,则 mmap 函数允许您从操作系统请求虚拟内存页面。以这种方式请求的内存将是您请求的数量(忽略用于跟踪这些分配的内核中占用的空间)。


根据“相等数量的内存”这个语句,人们可能会“看到”malloc可能会消耗更多的内存或者根本不消耗。通常情况下,内存是通过分页提供给应用程序的,如果我们关注从“外部”标记为程序分配的内存消耗,就有可能看到整个页面被分配(应用程序总体上需要更多堆空间)或没有页面(应用程序已经有足够的释放空间来存储数组在现有页面中)。 - Matt
在我看来,对于最完整的答案加一分。 - Matt
我认为这个回复有点离题,或者你是对的,但问题没有解释得很清楚。你基本上在解释幕后发生了什么,但这不是他在这里问的问题,如果我正在使用一种语言,并且我问你 int 的大小是多少,你应该能够根据语言规范说出一个数字,而不是关于操作系统或编译器如何工作的内容。此外,您对内存的组织方式控制非常有限,即使是 inline 选项也只是编译器的提示。 - user1717079

2
动态分配将需要至少几个额外的字节;除了5个int大小的元素,还需要指针变量所需的许多字节,以及可能需要一些额外的字节来跟踪已分配区域的大小,以便可以正确地进行释放。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接