C++之动态内存和引用

来源:互联网 发布:手机画板软件哪个好 编辑:程序博客网 时间:2024/06/11 19:19

1.动态内存

  C语言中通过malloc calloc realloc free 进行动态内存的分配和释放
  C++ 中除了对C提供的函数兼容之外,提供两个关键字 new / delete 实现动态内存的管理  如:见代码04maloc

 1.1 分配变量大小空间

  (1)申请指定数据类型变量大小的内存
     int* p = (int*)malloc(sizeof(int));
     int* p = new int;
  (2)申请空间并且初始化
     int* p = new int;*p = 200;
     int* p = new int(200); //使用200初始化
  (3)释放内存空间

        delete p;

p = NULL;   如:见代码 05new

 1.2 分配数组大小空间

 (1)申请 指定数据类型数组大小的空间
  int* p = new int[5];// 5表示数组的大小
 (2)申请空间并且初始化
  int* p = new int[5]{11,22,33,44,55};//使用大括号中的数据进行初始化,可能警告
 (3)释放内存空间
  delete[] p;//释放一段连续的内存
  p = NULL;  //见代码 05new
注意:
    释放内存之后,记得将指针置为空指针,p = NULL,这样做防止同一块内存被多次释放从而造成的double free 错误;
思考:
  1.如何申请多维数组空间
  2.int arr[2][3] = {0};

    int** p = arr;是否正确?为什么?

错误:

分析:arr 表示数组的首地址,也就是数组中第一个元素的地址,也就是第一行的地址; //&arr 表示整个二维数组的地址

      所以 //int** pp = arr;编译错误,类型不一致

1.3 申请多维数组空间

   当申请一个N维数组内存大小时,返回一个 N-1 维的数组指针
   int (*pArr)[4] = new int[3][4];
   int (*ppArr)[4][5] = new int[3][4][5];
 如:    见代码 06new.cpp

1.4 定位分配

  new (指针)类型(初值) ,表示在一个已经分配的内存空间申请内存
             |
       (指针) 表示分配内存的起始位置  如 :见代码:07new.cpp
 注意:

     new 出来的内存空间不一定在堆区,可能在栈区

2.  C++中 引用的概念 和使用

  2.1 引用的概念

      引用不是一种独立的数据类型,类似于C 中的指针,本质上就是起别名,但是本身不占有内存
   如:
      int a = 10;
      int& b = a; //表示给变量 a 起别名叫b, b = 10, a = 10; --> & 表示引用,不是取地址
      b++;  ====> b = 11, a = 11;
      int& c = b; 相当于给 a 起别名叫 c ---> c = 11; b = 11,a = 11;

  2.2  引用和指针的比较

     (1) 引用必须进行初始化,指针可以不初始化;  
        如: int a; 
            int& b; //error
            int* p; //ok
     (2) 引用不能为空,指针可以为空
           如: int& a = NULL;//error  0  --> 字面量,不可以改变
        从语法角度讲 NULL 相当于 0,然而 0 是字面量 ,不可以改变
        const int& a = NULL;// ok 常引用
        const int& a = 10;// ok  给10 起别名
        
        int* p = NULL; // ok 空指针 
     (3) 引用不可以更换目标,指针可以
        如: int a = 10;
            int& b = a;
            int m = 20;
            b = m; // 相当于赋值,本质上相当于 a = m;
            
            int* p = &a;  //ok
            p = &m;       //ok
     (4) 不能声明引用型数组(可以引用数组),可以声明指针型数组
           如: int a[5];   //ok
               int* pa[5]; //ok 指针型数组
               
               int& ra[5]; //error    不能声明引用型数组,因为引用本身就没有内存
               int (&ra)[5] = a;  //ok  引用数组
               
建议:
     尽量多使用引用,而少使用指针,因为指针容易出错,尤其是野指针非常危

2.3 引用的使用说明

   (1) 引用中 &的停靠问题
        int& a = b; == int & a = b; == int &a = b; 效果一样
    int a = 20;
    int& b = a; // 一个变量停靠在数据类型那侧
    int c = 10;
    int &d = a, &e = c; //多个变量停靠在变量名的那侧
   (2)起别名的方式来定义
   如:
    typedef int* PINT;
    PINT i,j; //i,j都是指针
   
    typedef int& RINT;
    RINT i = a,j = b; //i,j都是引用

 2.4  扩展

   (1)可以定义指向指针的指针,但是不可以定义指向引用的指针
  如: int a = 10;
     int* pa = &a;
     int** ppa = &pa;//ok 定义指向指针的指针
     
     int& b = a;
     int* ra = &b;   //对b 前面不可以有*   ==   int* ra = &a;//相当于定义了一个指向 a 的指针
     
     int& *rra = &b; //error  不可以定义指向引用的指针
   (2)可以定义引用指针的引用,不可以定义引用引用的引用
       (也就是说:可以给指针定义引用,不能给引用定义引用,不存在二级引用)
      如:
           int a = 10;
           int& b = a;
           
           int* pa = &a; ==  (typedef int* PINT;PINT pa = &a;PINT& ra = pa;=> int* &ra = pa; //ok)
           int* &ra = pa;//ok  给指针定义引用 ra = &pa;*ra = *pa;
           
           int&& c = b;  //error 不能给引用定义引用不存在二级引用
           可以这样: int& b = a;int& c = b; 看似是给引用b起了别名,其实质上还是给a 起的别名
           
   (3)可以定义指针数组,但是不能定义引用数组(声明引用数组),不过可以定义数组的引用(引用数组)
      如:
           int arr[5];
           int* pArr[5]; // 可以定义指针数组
           int& rArr[5]; //error   不能定义引用数组
           
           int (*pA)[5] = &arr; // 定义数组指针
           int (&rA)[5] = arr;  // ok 定义数组的引用 rA[0] = arr[0]
         如:见代码 08ref.cpp  08refun.cpp

 2.5 引用作为函数的参数

    (1)使用引用型参数可以在函数中对实参变量进行修改
    (2)使用引用型参数可以避免参数传递过程中数据的拷贝
    (3)通过将实参定义为常引用防止在函数内对实参进行修改,同时还可以接受常量型实参

    (4)使用引用型参数实际上就是传递地址 如:见代码 test.cpp

 2.6.引用作为函数的返回值  见代码: 01refReturn.cpp

    (1)永远不要返回一个局部变量的地址/引用
    (2)可以返回 全局/静态局部/成员(如结构体)/动态内存 /实参的引用  变量的引用,这种方式安全

0 0
原创粉丝点击