考虑以下两个代码:
#include<stdio.h>
void main() {
int num;
scanf("%d",&num);
int arr[num];
for(int i=0;i<num;i++){
arr[i] = i+1;
}
}
#include<stdio.h>
#include<stdlib.h>
void main() {
int num;
scanf("%d",&num);
int*p=(int*)malloc(num*size of(int));
for(int i=0;i<num;i++){
*(p+i) = i+1;
}
}
以上两段代码都是为用户给定的大小为num的数组分配内存,然后初始化。但第一个是数组的大小是可变的,所以在编译时编译器提供一些内存空间,它不是(可能)恰好是 num 但可能更多但在运行时 num 大小被分配给它稍后.
虽然对于 malloc one 的情况,不存在最初分配随机内存空间这样的问题,因此我们可以说 malloc 在这个特性方面更好,因此更适合使用?
以上两段代码都是为用户给定的大小为num的数组分配内存,然后初始化
在第一种情况下,
arr
被声明为局部变量,因此它使用堆栈中的内存,并且它仅在声明它的函数的持续时间内存在。如果该函数是 main
,那么它当然会在程序的生命周期内存在,但是在其他具有更短生命周期的函数中以这种方式声明的数组同样具有更短的生命周期。
在第二种情况下,数组被声明为“动态”——它使用堆中的内存而不是堆栈中的内存,并且即使在创建它的函数退出后也将继续存在。因为程序的堆空间通常比堆栈空间多得多,所以使用
malloc
也很有用,因为它允许创建更大的数组。
因此,例如,程序对从一个文件或多个文件中读取的数据进行操作是很常见的。想象一下编写一个函数来打开一个文件,将数据读入一个数组,并将该数组返回给调用者。如果该函数将数组声明为局部变量,则当函数退出时它将超出范围,您将无法将其返回给调用者。或者,您可以让调用者创建数组并将其传递给读取数据的函数,但是调用者必须提前知道文件中有多少数据,这并不总是可能的。此外,程序员可能事先不知道有多少文件,因此可能会读取多少数组。如果您在每次调用文件读取函数时动态创建一个数组,那么所有这些问题都会消失:您为每个文件获得一个新数组,您可以轻松地将数组返回给调用者,并且可以调整数组的大小以适应文件中的数据量。
malloc()
的可能优点:
它在超出范围后仍然存在(例如,您可以做
myPointer = malloc(foo); return myPointer;
但不能做int myArray[foo]; return myArray;
)。
它通常可以毫无问题地处理更大的分配(可用堆几乎总是大于可用堆栈空间)
它允许您优雅地处理错误(通过在出现故障时返回
NULL
,而不是在像int myArray[foo];
这样的事情导致您的堆栈溢出时导致未定义的行为)。
内存可以在分配后调整大小/重新分配。
malloc()
的可能缺点:
分配和释放内存时通常较慢
由于局部性,使用内存时可能会变慢
为避免内存泄漏,您必须稍后对内存进行
free()
,并且绝不能对内存进行多次free()
。这需要程序员付出一些额外的努力来保持跟踪(可能包括使用 valgrind 等工具来确保它是正确的)。