内存分配、动态内存、智能指针、动态数组

一、内存分配

有些操作对象只在程序运行时才能确定,这样编译时就无法为他们预定存储空间,只能在程序运行时,系统根据运行时的要求进行内存分配,这种方法称为动态存储分配。所有动态存储分配都在区中进行。

                                   

       ,在函数内部声明的所有变量都将占用栈内存。通常用来存储局部变量和函数参数。效率高,但是分配的内存容量有限。

  ,程序运行时可用于动态分配内存。内存使用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;//最后不要忘掉 释放掉开辟的指针数组

猜你喜欢

转载自blog.csdn.net/try_again_later/article/details/81584806