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)可以返回 全局/静态局部/成员(如结构体)/动态内存 /实参的引用 变量的引用,这种方式安全