1、动态分配的内涵
所谓动态内存分配,是指在程序运行时根据需要分配和释放内存,而不是在编译时确定内存需求。动态分配包括两方面的内涵:
- 在堆上分配内存。
对于linux的虚拟内存,可以分成以下5段:文本段、数据段(分初始化和未初始化数据段)、堆和栈。不使用动态分配定义一个变量,这个变量位于数据段(比如全局变量和静态变量)或者栈(比如函数体中的自动变量)中。关于虚拟内存,堆和栈,以后再专门开帖子讲。 - 在运行阶段而不是编译阶段分配内存。
对比:#define和typedef分别是在预编译和编译阶段工作。
2、malloc()和free()
2.1 空指针和强制类型转换
malloc()和free()是c语言的动态内存分配函数。具体定义如下:
void* malloc(size_t size);
void free(void* ptr);
注意malloc()返回的是空指针/通用指针。实际上,为了增加函数的泛用性,许多库的封装函数都返回的空指针:创建成功时,返回指向该内存的空指针;若失败,则返回NULL。返回空指针的好处是,在使用时可以通过数据类型强制转换,将空指针转换成任意类型的指针,这极大提高了函数的泛用性。返回空指针空指针的函数一般是通过强制转换的方式进行使用,如下例所示:
int *arr = (int *)malloc(10 * sizeof(int)); //返回的空指针强转为int型指针
if (arr == NULL) // 检查内存分配是否成功
{
printf("内存分配失败\n");
return 1;
}
......
free(arr);
2.2 等式两边的独立性
使用malloc()在堆中分配内存时,除了空指针和强制类型转换,还有必要分别对等式左右两边的语句及其关系进行说明。
int *ptr = (int *)malloc(10 * sizeof(int));
等式左边定义了一个int型指针arr,等式右边调用malloc()函数在堆中分配了一个长度为10的int型数组。等式两边是彼此独立的两个语句,因此也可以把它们拆开写,语法上也是成立的:
int *ptr;
(int *)malloc(10 * sizeof(int));
但是这样做是不妥的,因为这么做涉及到动态分配的另一个关键特性:动态分配的变量(包括数据、结构体等)是没有变量名的,必须在定义时将其地址赋给一个指针,使用指针来操作变量。如果使用malloc()单独进行内存分配,那么所分配的内存是无法操作的,因为既不知道变量名,也不知道其具体位置。因此,实际进行内存分配时,都是指针定义和动态内存分配写在一个式子里边的。
3、new和delete
c++中,使用new和delete进行内存动态分配。和malloc()和free()一样,等式两边是彼此独立的两个语句,同样可以把它们拆开写。
和malloc()和free()不同的是,malloc()和free()是函数,但new和delete是关键字。并且new
关键字不仅仅分配内存,还会调用对象的构造函数来初始化对象。
另外还有一点很关键:delete释放的是堆中内存,而不是指向该内存的指针本身,后续该指针可以被继续使用。
动态分配基本数据类型的变量:
int *ptr = new int;
……
delete ptr;
动态分配数组:
int *ptr = new int [10];
……
delete [] ptr;
4、内存泄露
内存泄漏(Memory Leak)是指在计算机程序中,已分配的内存由于某种原因未能被释放,导致内存资源逐渐耗尽的现象。其实就是使用malloc()和free()(cpp中是new和delete)所存在的风险,更具体地说,是仅用指针来操作和锚定内存所存在的风险。
发生内存泄露存在两种常见的情况:
- 在函数中分配了一个堆,但是函数结束前忘记了使用free()或delete释放内存。所以malloc()和free()一定要成对使用。
这是什么道理呢?我们知道,在函数体中定义的变量是自动变量,存放在对应的函数栈中,其生命期会随着函数调用的结束而结束。因此,随着函数调用的结束,在函数体内定义的用于操作和锚定动态内存的指针也就随之湮灭了。
而使用malloc()和new动态分配内存时,是在堆中进行分配,而不是分配在函数栈中。因此,即便动态分配所创建的内存并不会随着函数调用的结束而自动释放。
于是就造成了这么一个情况:如果没有调用free()或delete及时释放内存,那么函数调用结束之后,原本唯一用于操作和锚定内存的指针消失了,而没有被释放的堆中内存就会一直存在下去,并且没有任何手段能找到它,这块内存成为了无用的内存碎片。每调用一次函数,就会产生一个内存碎片,久而久之,当内存被分割得支离破碎,再也找不到可被有效利用的内存块时,就会发生内存泄露。 - 指向堆的指针被覆盖,指向了其他地方,导致无法再找到所分配的堆内存。
对于这种情况,可以使用const常量指针。如果试图将pt指向别处,那么系统将会编译报错。
int* const ptr = (int *)malloc(10 * sizeof(int)); //c
int* const ptr = new int; //cpp
标签:类型转换,malloc,int,free,动态分配,内存,指针
From: https://blog.csdn.net/hccgso1212/article/details/141217644