我们过去掌握的内存开辟方式有:
int val=20; //在栈空间上开辟4个字节
char arr[10]={0};//在栈空间上开辟10个字节的连续空间
但是上述的开辟空间的方式有两个特点:
- 空间开辟大小是固定的。
- 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译 时开辟空间的方式就不能满足了。 这时候就只能试试动态存开辟了。
1.malloc
void* malloc (size_t size);
在内存堆上,申请一系列连续的空间,并返回指向这块空间的指针。(若失败,则返回空指针);
2.free
void free (void* ptr)
这个函数是专门用来释放和回收你申请的动态空间的。(如果参数为空指针,那么就什么都不做)。
注意: 我们必须要对我们申请的动态空间进行释放,不然会造成内存泄漏(内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。)
3.calloc
void* calloc (size_t num,size_t size);
函数功能是为num个大小为size的元素开辟一块连续的空间,并且把每个字节都初始化为0。
其实光看前面这个函数和malloc的作用一样,但是它把每个字节都初始化为0了,这个功能往往都是没用的,所以我们一般不用这个函数。一般都是malloc后,自己手动初始化。当然,这个函数也要free();
4.realloc
void* realloc (void* ptr, size_t size);
ptr是要调整的内存地址
size为调整后的大小
这个函数的功能就是扩大过去申请的空间。当我们原来malloc空间发现不够用的时候,这个函数便可以用来扩大原动态内存。
需要注意的是:当申请的内存 紧随其后的内存若是可用的,那么这个函数就会在它后面直接开辟,若是没有,这个函数就会在内存重新找一块地址用来放下整个数据,然后自动把原申请的空间释放掉。
我们举一些常见动态内存错误:
void test()
{ int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
void test() {
int i = 0;
int *p = (int *)malloc(10*sizeof(int));
if(NULL == p) { exit(EXIT_FAILURE); }
for(i=0; i<=10; i++) {
*(p+i) = i;//当i是10的时候越界访问
}
free(p);
}
void test() {
int a = 10;
int *p = &a;
free(p); //错误, 对非动态开辟内存使用free释放
}
void test() {
int *p = (int *)malloc(100);
p++; free(p); //p不再指向动态内存的起始位置 ,系统不知释放哪的内存
}
void test() {
int *p = (int *)malloc(100);
free(p);
free(p); //重复释放 ,肯定凉凉,那块的地址你在非法访问
}