1.初步了解内存中各个区间存储的数据特征
1.栈区:存储一些局部变量、函数参数、返回值等,跟函数栈振有关,出了作用域,生命周期结束。
2.堆区:用于动态开辟空间,如果不主动销毁空间,则程序运行结束,生命周期结束。
3.数据段(静态区):static修饰的静态变量和全局变量,程序运行结束,生命周期结束。
4.代码段(常量区):可执行的代码和常量。
练习
int globalVar = 1;static int staticGlobalVar = 1;void Test(){static int staticVar = 1;int localVar = 1;int num1[10] = { 1, 2, 3, 4 };char char2[] = "abcd";const char* pChar3 = "abcd";int* ptr1 = (int*)malloc(sizeof(int) * 4);int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);free(ptr1);free(ptr3);}
选项 : A . 栈B . 堆C . 数据段 ( 静态区 ) D . 代码段 ( 常量区 ) globalVar 在哪里? __1__staticGlobalVar 在哪里? __2__ staticVar 在哪里? __3__localVar 在哪里? __4__ num1 在哪里? __5__ char2 在哪里? __6__* char2 在哪里? __7_ pChar3 在哪里? __8__* pChar3 在哪里? __9__ ptr1 在哪里? __10__ * ptr1 在哪里? __11__
1.C 2.C 3.C4. A 5.A6.A7. A 8.A9.D10.A11.B
结合上图可以得知,cha2其本身存放在栈区,指针指向栈区中数组首元素的地址,再将静态区中”abcd”赋值给数组,所以*char指向的元素在栈区!!! pChar3其本身存放在栈区,指向静态区中存放”abcd”字符串的首地址!!!
2.c语言实现内存管理
2.1malloc
在堆上开一快符合你预期大小的一块空间,并且返回指向该地址空间的指针
void* malloc (size_t size);
size:开多大的空间,单位是字节
2.2realloc
如果malloc开辟出来的空间开少了,realloc可以在堆上重新开一块符合你预期大小的空间,并返回指向该空间的指针
void*realloc (void * ptr,size_t size);
ptr:初始空间的地址
size:将空间开辟到多大
2.3calloc
用于对开辟的空间进行初始化,calloc会将开辟的空间中每个元素初始化为0
void*realloc (size_t num,size_t size);
num:分配的元素数量
size:每个元素的大小
3.c++实现内存管理
3.1 new/delete new []/delete []
在c++中,有两对操作符new/delete、new []/delete [],他们的作用是负责开空间和释放空间!!!
new作用跟malloc类似,delete作用跟free类似
new和delete在面对自定义类型时会去调用构造函数和析构函数
new =先申请对象空间再调用构造函数
delete =先调用析构函数再释放对象空间
3.1.1内置类型
当需要开一个整形的空间时。
int main(){ //mallocint* p1 = (int*)malloc(sizeof(int));//new开空间用法跟malloc不同,但是作用相同,都是负责开空间!!!int* p2 = new int;//freefree(p1);//deletedelete(p2);return 0;}
当需要开多个空间时例如开10个int类型的空间 需要加上[]
int main(){int* p1 = (int*)malloc(sizeof(int)*10);int* p2 = new int[10];free(p1);delete[](p2);return 0;}
3.1.2自定义类型
new和delete在面对自定义类型时会去调用构造函数和析构函数
new =先开空间再调用构造函数
delete =先调用析构函数再释放空间
class Stack{public:Stack(int capacity = 4){_a = new int[capacity];int _top = 0;int _capacity = capacity;}~Stack(){delete (_a);_a = nullptr;_top = 0;_capacity = 0;}private:int* _a;int _top;int _capacity;};int main(){Stack* p2 = new Stack;//new先开空间 再去调用构造函数delete(p2);//delete先调用析构函数,再去释放空间return 0;}
如果需要开10个Stack类型的空间用new[]和 delete[]
int main(){Stack* p2 = new Stack[10];//new先开空间 再去调用构造函数delete[](p2);//delete先调用析构函数,再去释放空间return 0;}
3.2new/delete底层实现原理
3.2.1全局函数 operator new/operator delete
要知道原理,我们就得先知道operatot new / operator delete这两个全局函数
在c++中,有这样两个全局函数,他们的作用跟malloc、free类似,都是负责开空间和释放空间!!!
注意:operator new /operatordelete不是new/delete的重载,而是两个全局函数!!!
我们知道malloc申请空间失败的时候,会返回空。而operator new申请空间失败的时候则会抛异常。我们可以理解为operator是封装的malloc。
也就是说operatornew和mclloc除了申请空间失败的处理方法不同,其他的用法以及功能是相同的!!!
operatordelete可以理解为跟operatornew对应,其用法和功能跟free完全一样!!!
int main(){Stack* p1 = (Stack*)malloc(sizeof(Stack));free(p1); //operator new底层用的是mallocStack* p2 = (Stack*)operator new (sizeof(Stack));//operator delete底层用是freeoperator delete(p2);return 0;}
3.2.2 new/delete和operatornew/operator delete的关系
new = 1.申请对象空间 + 2.调用构造
delete = 1.调用析构 + 2.释放对象空间
在底层原理上,new的第一步申请对象空间底层就是调用operator new函数,
operator的第二步释放对象空间底层就是调用operatoroperator函数.
也就是说下面两段不同的代码,起到的作用都是相同的
int main(){Stack* p1 = new Stack;delete (p1);//等价于newStack* p2 = (Stack*)operator new (sizeof(Stack));//定位new显示调用构造函数new(p2)Stack;//等价于deletep2->~Stack();operator delete(p2);return 0;}
我们到汇编语言的角度证明一下