1. C/C++内存分布
在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
- 栈,在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
- 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
- 自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free来结束自己的生命的。
- 全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。
- 常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改。
2. C语言中动态内存管理方式:malloc/calloc/realloc/free
malloc:
1.引用头文件stdlib.h
2.使用malloc()开辟内存空间
3.判断malloc()的返回值是否为空指针
4.使用malloc()开辟好的内存空间
5.使用free()释放malloc()开辟的内存空间
6.将指针置为NULL
动态内存分配内存图
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//向内存申请40字节的空间,以整型的形式进行使用和管理
int* ptr = (int*)malloc(40);
//对malloc返回值进行判断
if (NULL == ptr)
{
perror("malloc\n");
return 1;
}
//使用开辟好的内存空间
int i = 0;
for (i = 0; i < 10; i++)
{
*(ptr + i) = i;
}
//释放空间
free(ptr);
//将指针置为空指针
ptr = NULL;
return 0;
}
有几个点需要注意:
1.使用malloc()后,要对返回值进行判断
2.使用结束后,要用free()对malloc()开辟的内存空间进行释放,最重要的是free()的参数是指向malloc()开辟内存空间的起始地址
3.内存空间释放后,将指针ptr置为空指针,否则会造成野指针问题。
calloc:
1.calloc()函数向内存申请一块连续的空间,并将内存空间都初始化为0。
2.calloc()参数num表示分配num个元素的空间,size表示每个元素的大小,单位为字节。
3.calloc()函数的返回值为void*类型,如果内存空间开辟成功,则返回开辟的内存空间的起始地址;如果失败,则返回空指针(NULL)。
calloc()和malloc()的区别只在于calloc()会在返回地址之前把申请的空间的每个字节初始化为0。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//向内存申请40字节的空间,以整型的形式进行使用和管理
int* ptr = (int*)calloc(10 , sizeof(int));
//对malloc返回值进行判断
if (NULL == ptr)
{
perror("calloc\n");
return 1;
}
//使用开辟好的内存空间
int i = 0;
for (i = 0; i < 10; i++)
{
*(ptr + i) = i;
}
//释放空间
free(ptr);
//将指针置为空指针
ptr = NULL;
return 0;
}
calloc()的使用方法和malloc()的使用方法很相似,区别是calloc()的参数形式和malloc()的参数形式书写不同,另一个区别calloc()会在返回地址之前把申请的空间的每个字节初始化为0,而malloc()只开辟空间,不进行初始化。
realloc:
1.realloc()函数的作用是对指针ptr指向的动态开辟的内存空间的大小进行调整。
2.realloc()的参数ptr,指向的是先前用malloc()、calloc()、realloc()开辟的内存空间的起始地址,或者,它可以是一个空指针,在这种情况下分配一个新的块(就像调用malloc一样)。
3.realloc()的参数size,表示调整后内存空间的大小。
4.realloc()的返回值是一个指向重新分配的内存空间的指针,它可以是与ptr相同的,也可以是一个新的位置。此指针的类型为void*,可以将其强制转换为所需的数据指针类型,以便可解引用。
5.如果函数分配请求的内存空间失败,则返回空指针,并且参数ptr所指向的内存块没有被释放(它仍然有效,且其内容不变)。
realloc()开辟空间存在两种情况 :
- 情况一:原有空间之后有足够大的空间
- 如果原有的内存空间之后有足够大的空间,要扩展内存就直接在原有内存之后追加内存空间,原来空间的数据不会发生变化
- 情况二:原有的空间之后没有足够大的空间
如果是情况二的时候,原有空间之后没有没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间,将原来空间的数据拷贝到新开辟的内存空间中存放,并且将原来的内存空间释放。这样函数返回的是一个新的内存地址。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
//向内存申请40字节的空间,以整型的形式进行使用和管理
int* ptr = (int*)malloc(40);
//对malloc返回值进行判断
if (NULL == ptr)
{
perror("malloc\n");
return 1;
}
//使用开辟好的内存空间
int i = 0;
for (i = 0; i < 10; i++)
{
*(ptr + i) = i;
}
//对内存空间进行扩容
int* p = (int*)realloc(ptr, 80);
//当realloc开辟空间失败时,返回的是NULL
if (p != NULL)
{
ptr = p;
p = NULL;
}
//对新开辟的空间进行使用
for (i = 10; i < 20; i++)
{
*(ptr + i) = i;
}
//释放空间
free(ptr);
//将指针置为空指针
ptr = NULL;
return 0;
}
3. C++内存管理方式
new/delete操作内置类型
void Test()
{
// 动态申请一个int类型的空间
int* ptr4 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr5 = new int(10);
// 动态申请10个int类型的空间
int* ptr6 = new int[3];
delete ptr4;
delete ptr5;
delete[] ptr6;
}
4. operator new与operator delete函数
new和delete是用户进行动态内存申请和释放的操作符;
operator new和operator delete是系统提供的全局函数;
new在底层调用operator new全局函数来申请空间;
delete在底层通过operator delete全局函数来释放空间;
operator new实际上也是通过malloc来申请空间,如过malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常;
operator delete最终通过free来释放空间;
new和delete的实现原理
其中new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间;
new在申请空间失败后会抛异常,malloc会返回NULL;
自定义类型:
new的原理:
1、调用operator new函数申请空间;
2、在申请的空间上执行构造函数,完成对象的构造;
delete的原理:
1、在空间上执行析构函数,完成对象中资源的清理工作;
2、调用operator delete函数释放对象的空间;
new T[N]的原理:
1、调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请;
2、在申请的空间上执行N次构造函数;
**delete[]的原理: **
1、在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理;
2、调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间;