可能重复:
Malloc还是普通数组定义?
我们了解到C和动态变量中存在动态记忆:
#include <stdio.h>
int a = 17;
int main(void)
{
int b = 18; //automatic stack memory
int * c;
c = malloc( sizeof( int ) ); //dynamic heap memory
*c = 19;
printf("a = %d at address %xn", a, &a);
printf("b = %d at address %xn", b, &b);
printf("c = %d at address %xn", *c, c);
free(c);
system("PAUSE");
return 0;
}
我如何知道要使用哪种类型的内存?我什么时候吃的?
在以下情况下使用动态:
-
当你需要大量记忆的时候。典型的堆栈大小是1MB,所以任何大于50-100KB的东西都应该更好地动态分配,否则就有崩溃的风险。有些平台的限制甚至更低。
-
当函数返回后内存必须存在时。当函数结束时,堆栈内存被破坏,动态内存在需要时被释放。
-
当你构建一个未知(即可能变大)大小的结构(如数组或图)时,它会动态变化,或者很难预先计算。动态分配允许你的代码在任何时候,只有在你需要的时候,才能自然地逐块请求内存。在
for
循环中,不可能重复请求越来越多的堆栈空间。
否则,首选堆栈分配。它速度更快,不会泄漏。
只有在运行时才知道分配的大小时,才使用动态内存。
例如,您要求用户输入名称(比如最多10个名称)并将它们存储在字符串数组中。由于您不知道用户将提供多少名称(仅在运行时),因此只有在您知道要分配多少名称之后,您才能分配数组,因此您将使用动态分配。
当然,您可以使用固定大小的10的数组,但对于较大的数量,这将是浪费
如果您不知道程序在编译时需要分配多少内存,请使用动态内存分配。
例如,int a[n]
会将您的数组大小限制为n。此外,无论您是否使用它,它都会分配n x 4字节的内存。这是在堆栈上分配的,并且在编译时必须知道变量n。
另一方面,int *a = (int *)malloc(n * sizeof (int))
在运行时、堆上分配,而n
只需要在运行时知道,而不一定在编译时知道。
这也可以确保您分配的内存与您真正需要的内存一样多。但是,由于是您在运行时分配的,因此必须使用free
进行清理。
您应该在以下情况下使用动态内存:
- 如果您希望您的对象在创建它的范围之外继续存在
- 通常,堆栈大小是有限的,因此,如果您的对象占用了大量内存,那么您可能会耗尽堆栈空间,在这种情况下,通常会进行动态内存分配
请注意,c99标准在C中引入了可变长度阵列(VLA),因此您不需要仅仅因为事先不知道阵列尺寸而使用动态内存分配(当然,除非是上面提到的#2
)
最好尽可能避免动态内存分配,因为这意味着显式管理内存,而不是该语言提供的自动机制。显式内存管理意味着你容易犯更多的错误,这可能会导致灾难性的影响
已经说过,动态内存分配不能总是避免,必须在必要时使用(上面提到的两种情况)。
如果你可以在没有动态分配的情况下编程,就不要使用它!
但总有一天你会被阻止,解除阻止的唯一方法是使用动态分配,然后现在你可以使用它
Als提出了一个有趣的观点,即如果您的对象需要在创建它的范围之外持久存在,则应该从堆中分配内存。在上面的代码中,您根本不需要从堆中分配内存。你可以这样重写:
#include <stdio.h>
int a = 17;
int main(void)
{
int b = 18; //automatic stack memory
int c[1]; // allocating stack memory. sizeof(int) * 1
c[0] = 19;
printf("a = %d at address %xn", a, &a);
printf("b = %d at address %xn", b, &b);
printf("c = %d at address %xn", c[0], c);
system("PAUSE");
return 0;
}
事实上,作为C99标准(可变长度数组)的一部分,您可以使用[]
运算符为堆栈上的数组分配动态空间,就像通常创建数组一样。您甚至不需要在编译时知道数组的大小。编译器只会根据请求的分配空间调整esp寄存器(适用于x86
机器),就可以开始了。