在堆栈上增长数组
Growing an array on the stack
这本质上是我的问题。在一个函数的生命周期中,我生成一些整数,然后在一个算法中使用整数数组,该算法也是同一函数的一部分。整数数组只会在函数内使用,所以将数组存储在堆栈上自然是有意义的。
问题是在生成所有整数之前我不知道数组的大小。
我知道如何在堆栈上分配固定大小和可变大小的数组。但是,我不知道如何在堆栈上增加数组,这似乎是解决我的问题的最佳方法。我相当确定这在汇编中是可能的,您只需增加堆栈指针并为每个生成的 int 存储一个 int,因此 int 数组将位于堆栈帧的末尾。这在 C 中可以做到吗?
我不同意你的断言"so naturally it makes sense to store the array on the stack"。堆栈内存实际上是为您在编译时知道大小时而设计的。我认为动态内存是解决问题的方法
为了解决您的问题,动态内存分配看起来很理想。
int *a = malloc(sizeof(int));
并取消引用它以存储值。
每次需要将一个新整数添加到现有整数列表中时
int *temp = realloc(a,sizeof(int) * (n+1)); /* n = number of new elements */
if(temp != NULL)
a = temp;
使用此内存后free()
它。
不要在堆栈上使用动态数组(比较Why is the use of alloca() not considered good practice?),最好使用malloc
从堆中分配内存并使用realloc
调整大小。
C 编译器的内部结构要求堆栈大小在编译时是固定的或可计算的。自从我使用 C(现在是 C++ 转换)以来已经有一段时间了,我不知道这是为什么。 http://gribblelab.org/CBootcamp/7_Memory_Stack_vs_Heap.html 对两种方法的优缺点进行了有用的比较。
我很欣赏你的汇编代码类比,但 C 在很大程度上是由操作系统管理的,如果这有意义的话,imposes/provides 任务、进程和堆栈符号。
C 没有定义 "stack" 是什么。它只有静态、自动和动态分配。静态和自动分配由编译器处理,只有动态分配才能将控制权交到您手中。因此,如果你想手动释放一个对象并分配一个更大的对象,你必须使用动态分配。
永远不要使用 alloca()
恕我直言,这一点在标准参考文献中做得不够好。
一个经验法则是:
If you're not prepared to statically allocate the maximum possible size as a
fixed length C array then you shouldn't do it dynamically with alloca()
either.
为什么?您试图避免 malloc()
的原因是性能。
alloca()
会更慢并且在任何情况下都不起作用静态分配将失败。它通常也比 malloc()
更不可能成功。
有一点是肯定的。静态分配最大值将超过 malloc()
和 alloca()
。
静态分配通常在空操作附近该死。大多数系统无论如何都会为函数调用推进堆栈指针。距离有多远没有明显差异。
所以你告诉我的是你关心性能但想阻止空操作解决方案?想想你为什么会有这种感觉。
极有可能是您担心分配的大小。
但如前所述,它是免费的,但会被收回。有什么好担心的?
如果担心 "I don't have a maximum or don't know if it will overflow the stack" 那么你不应该使用 alloca()
因为你没有最大值并且知道它是否会溢出堆栈。
如果您确实有最大值并且知道它不会破坏堆栈,那么静态分配最大值并回家。免费午餐 - 记得吗?
这使得 alloca()
要么是错误的,要么是次优的。
每次您使用 alloca()
时,您要么是在浪费时间,要么是在一种难以测试的任意缩放上限中进行编码,该上限会安静地休眠,直到事情真正重要,然后 f**k up某人的一天。
不要。
PS: 如果你需要一个大的 'workspace' 但 malloc()
/free()
开销是一个瓶颈例如在一个大循环中重复调用,然后考虑在循环外分配工作空间并将其从一个迭代带到另一个迭代。如果发现 'big' 情况,您可能需要重新分配工作区,但通常可以将分配数除以 100 甚至 1000。
脚注:
必须有一些理论算法,其中 a() 调用 b() 并且如果 a() 需要大量环境 b() 则不需要,反之亦然。
在这种情况下,可能会出现某种奇怪的附加赛,其中堆栈溢出被 alloca()
阻止了。我从未听说过或见过这样的算法。收到合理的标本将不胜感激!
这本质上是我的问题。在一个函数的生命周期中,我生成一些整数,然后在一个算法中使用整数数组,该算法也是同一函数的一部分。整数数组只会在函数内使用,所以将数组存储在堆栈上自然是有意义的。
问题是在生成所有整数之前我不知道数组的大小。
我知道如何在堆栈上分配固定大小和可变大小的数组。但是,我不知道如何在堆栈上增加数组,这似乎是解决我的问题的最佳方法。我相当确定这在汇编中是可能的,您只需增加堆栈指针并为每个生成的 int 存储一个 int,因此 int 数组将位于堆栈帧的末尾。这在 C 中可以做到吗?
我不同意你的断言"so naturally it makes sense to store the array on the stack"。堆栈内存实际上是为您在编译时知道大小时而设计的。我认为动态内存是解决问题的方法
为了解决您的问题,动态内存分配看起来很理想。
int *a = malloc(sizeof(int));
并取消引用它以存储值。 每次需要将一个新整数添加到现有整数列表中时
int *temp = realloc(a,sizeof(int) * (n+1)); /* n = number of new elements */
if(temp != NULL)
a = temp;
使用此内存后free()
它。
不要在堆栈上使用动态数组(比较Why is the use of alloca() not considered good practice?),最好使用malloc
从堆中分配内存并使用realloc
调整大小。
C 编译器的内部结构要求堆栈大小在编译时是固定的或可计算的。自从我使用 C(现在是 C++ 转换)以来已经有一段时间了,我不知道这是为什么。 http://gribblelab.org/CBootcamp/7_Memory_Stack_vs_Heap.html 对两种方法的优缺点进行了有用的比较。
我很欣赏你的汇编代码类比,但 C 在很大程度上是由操作系统管理的,如果这有意义的话,imposes/provides 任务、进程和堆栈符号。
C 没有定义 "stack" 是什么。它只有静态、自动和动态分配。静态和自动分配由编译器处理,只有动态分配才能将控制权交到您手中。因此,如果你想手动释放一个对象并分配一个更大的对象,你必须使用动态分配。
永远不要使用 alloca()
恕我直言,这一点在标准参考文献中做得不够好。
一个经验法则是:
If you're not prepared to statically allocate the maximum possible size as a fixed length C array then you shouldn't do it dynamically with
alloca()
either.
为什么?您试图避免 malloc()
的原因是性能。
alloca()
会更慢并且在任何情况下都不起作用静态分配将失败。它通常也比 malloc()
更不可能成功。
有一点是肯定的。静态分配最大值将超过 malloc()
和 alloca()
。
静态分配通常在空操作附近该死。大多数系统无论如何都会为函数调用推进堆栈指针。距离有多远没有明显差异。
所以你告诉我的是你关心性能但想阻止空操作解决方案?想想你为什么会有这种感觉。
极有可能是您担心分配的大小。
但如前所述,它是免费的,但会被收回。有什么好担心的?
如果担心 "I don't have a maximum or don't know if it will overflow the stack" 那么你不应该使用 alloca()
因为你没有最大值并且知道它是否会溢出堆栈。
如果您确实有最大值并且知道它不会破坏堆栈,那么静态分配最大值并回家。免费午餐 - 记得吗?
这使得 alloca()
要么是错误的,要么是次优的。
每次您使用 alloca()
时,您要么是在浪费时间,要么是在一种难以测试的任意缩放上限中进行编码,该上限会安静地休眠,直到事情真正重要,然后 f**k up某人的一天。
不要。
PS: 如果你需要一个大的 'workspace' 但 malloc()
/free()
开销是一个瓶颈例如在一个大循环中重复调用,然后考虑在循环外分配工作空间并将其从一个迭代带到另一个迭代。如果发现 'big' 情况,您可能需要重新分配工作区,但通常可以将分配数除以 100 甚至 1000。
脚注:
必须有一些理论算法,其中 a() 调用 b() 并且如果 a() 需要大量环境 b() 则不需要,反之亦然。
在这种情况下,可能会出现某种奇怪的附加赛,其中堆栈溢出被 alloca()
阻止了。我从未听说过或见过这样的算法。收到合理的标本将不胜感激!