一、内存分配
有些操作对象只在程序运行时才能确定,这样编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。所有动态存储分配都在堆区中进行。
栈,在函数内部声明的所有变量都将占用栈内存。通常用来存储局部变量和函数参数。效率高,但是分配的内存容量有限。
堆,程序运行时可用于动态分配内存。内存使用new进行分配使用delete或delete[]释放。
自由存储区,使用malloc进行分配,使用free进行回收。和堆类似。
静态存储区,全局变量和静态变量 static 被分配到同一块内存中。
常量存储区,他们里面存放的是常量,不允许修改。
区分堆和栈
实例
void f()
{ int* p=new int[5]; }
包含了堆和栈,new表明分配了一块堆内存,指针p存放在栈内存中。“在栈内存中存放了一个指向一块堆内存的指针p。”
//main.cpp 程序代码区
int a = 0; //全局初始化区
char *p1; //全局未初始化区
int main()
{
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区,p3在栈上。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
管理方式:栈:是由编译器自动管理,无需我们手工控制;堆:释放工作由程序员控制,容易产生memory leak。
空间大小:一般来讲在32位系统下,默认的栈空间大小是1M,堆内存可以达到4G的空间。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应。
生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
二、动态内存与智能指针
动态内存:new:为对象分配空间并指向该对象的指针 delete:接受一个动态对象的指针,释放该对象,释放与之关联的内存。
智能指针:分别为shared_ptr允许多个指针指向同一个对象,unique_ptr独占所指向的对象。
1、智能指针shared_ptr类(也是模板)
在最后一个shared_ptr销毁时内存会自动释放
创建智能指针:
shared_ptr<string> p1; //指向string
make_shared函数:
shared_ptr<int> p = make_shared<int>(42); //指向一个42的int的shared_ptr
auto p = make_shared<int>(42);
auto q(p) // 拷贝,该对象有两个引用者
p=q // 赋值,递增q指向对象的引用计数,递减p的引用技术。
p原来指向的对象已经没有引用者,自动释放
2、new和delete(记得释放内存)
new:返回一个指向该对象的指针,分配内存
int* pi=new int; //默认初始化为空int,pi指向一个未初始化的无名对象
int* pi=new int(); //值初始化为0
int* pi=new int(1024); //直接初始化,指向的对象为1024
vector<int>* pi=new vector<int>{1,2,3,4,5} //列表初始化
const int* pi=new const int(1024); //指向动态分配的const对象
delete:销毁指针指向对象,释放内存。
// 指向动态内存的指针或是空指针。
double* pd=new double(33);
delete pd;
// 错误!!!静态对象
double *pi=&i;
delete pi;
三、动态数组
c++要求定义数组时,必须明确给定数组的大小,要不然编译通不过
int Array[5];正确
int i=5;
int Array[i]; 错误 因为在编译阶段,编译器并不知道 i 的值是多少
那么,我们该如何解决定义长度未知的数组呢?
答案是:new 动态定义数组
一维数组
//动态分配,数组长度为m
int* p=new int[10];//默认初始化
int* p=new int[10]();//值初始化
int* p=new int[10]{0,1,2,3,4,5};//列表初始化
//释放内存
delete [] p;
二维数组
// 假定数组第一维长度为 m, 第二维长度为 n
// 定义指针数组
int** p = new int *[m];
//为行指针分配空间
for( int i=0; i<row; i++ )
{
//为每行分配空间(每行有col个元素)
p[i] = new int [col] ;
}
//输入二维数组的数
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
cin>>arr[i][j];
//输出
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
cout>>arr[i][j]<<"";
cout<<endl;
//释放
for( int i=0; i<row; i++ )
{
delete [] p[i]; // 要在指针前加[] , 否则的话 只释放p[i]所指的第一个单元所占的空间
}
delete [] p;//最后不要忘掉 释放掉开辟的指针数组