栈和堆是进程内存空间中非常重要的2块区域。栈用于存放程序临时创建的局部变量;堆用于存放进程运行中被动态分配的内存段。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上;当利用free等函数释放内存时,被释放的内存从堆中被剔除。
1、C动态内存分配
C语言动态内存分配相关的库函数有以下几个:
malloc、calloc、realloc、free这4个函数。
(1)malloc
void *malloc(unsigned int size);
函数的作用是分配一个长度为size个字节的连续空间。函数的返回值是所分配区域的第一个字节的地址。
如果函数未能成功地执行,则返回空指针NULL。
int* pv = (int*)malloc(5*sizeof(int));
if(pv != NULL){ //先检查函数调用是否成功
for (int i = 0; i < 5; i++) {
pv[i] = i + 1;
}
}
(2)calloc
void *calloc(unsigned n, unsigned size);
函数的作用是分配n个长度为size个字节的连续空间,并同时清空内存。可用来给数组开辟动态存储空间。
int *p = (int*)calloc(8, 4);
分配8*4个字节的存储空间。
如果用malloc来达到同calloc的效果,则代码需要这么写:
int *p = (int*)malloc(8*4); //malloc不会清空内存,可调用memset清空内存
memset(p, 0, 8*4);
(3)realloc
void *realloc(void *p, unsigned int size);
如果已经通过malloc函数或calloc函数分配了空间,想改变其大小,可以用realloc函数重新分配。
int* pi = (int*)calloc(8, 4);
*pi = 4;
*(pi + 1) = 5;
printf(" %d\n", *(pi + 1)); //输出5
realloc(pi, 64);
printf(" %d\n", * (pi + 1)); //输出5。所以realloc不会破坏原来存储的数据
return 0;
realloc函数要点总结:
(3.1)realloc函数可以扩大存储空间,也可以缩小存储空间。
(3.2)realloc函数重新分配了新地址,旧指针无需调用free。
(3.3)一定不要这样调用:ptr = realloc(ptr, size),这样会使原来的ptr丢失而导致内存泄漏。
(3.4)如果调用realloc失败,返回NULL;但原内存空间不受影响。
(3.5)realloc很耗资源,能不用就不用。
(4)free
void free(void *ptr);
函数的参数是指向由malloc、calloc、realloc函数分配的内存地址,调用后这块内存返回给堆空间。
int *pi = (int*)malloc(4);
...
free(pi);
调用free函数后,指针pi指向的内存空间被释放,但指针pi依然指向这块已被释放的地址。
此时,需要把NULL赋给指针pi:pi = NULL
重复free置为NULL的指针不会出错,但重复free非NULL指针一定会报错。
int* pi = (int*)calloc(8, 4);
free(pi);
pi = NULL;
free(pi); //重复free不会报错
free(pi); //重复free不会报错
2、C++动态内存分配
(1)new、delete
C++中通过new关键字进行动态内存申请,用delete关键字进行内存释放。
malloc、calloc、realloc函数是按字节数分配存储空间的;
但用new内存分配是基于类型进行的。
int* pi = new int(1); //分配内存时把值初始化为1
delete pi;
int* pv = new int[10];
delete[] pv;
(2)new关键字与malloc函数的区别
new关键字 |
malloc函数 |
new关键字是C++的一部分 |
malloc是由C库提供的函数 |
new以具体类型为单位进行内存分配 |
malloc以字节为单位进行内存分配 |
new在申请单个类型变量时可进行初始化 |
malloc不具备内存初始化的特性 |
(3)动态内存分配异常机制
用malloc分配内存空间可能会失败,用new分配内存空间也可能失败。C++提供了两种标准机制来检查分配是否成功。
(3.1)bad_alloc异常
默认情况下,在分配失败时会抛出bad_alloc类型的异常,如果此异常未处理,则程序终止。
int* pv = new int[10];
(3.2)nothrow
使用nothrow后,在内存分配失败时,不抛出bad_alloc异常;此时new返回的空指针。
int* pv = new (nothrow) int[10];
if (pv != nullptr) {
... ...
}